<commit_before>/*
 * Copyright (©) 2015 Nate Rosenblum
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/thread.h>

#include <atomic>
#include <cassert>
#include <condition_variable>
#include <mutex>

#include "event_handler_impl.h"
#include "libevent_event_handler.h"
#include "wte/event_base.h"
#include "wte/event_handler.h"

namespace wte {

class LibeventEventBase final : public EventBase {
public:
    LibeventEventBase();
    ~LibeventEventBase();

    void loop(LoopMode mode) override;
    void stop() override;
    void registerHandler(EventHandler*, What) override;
    void unregisterHandler(EventHandler*) override;
private:
    event_base *base_;
    std::atomic<bool> terminate_;

    struct {
        std::mutex mutex;
        std::condition_variable cv;
        bool finished = false;
    } await_;
};

LibeventEventBase::LibeventEventBase() : base_(event_base_new()),
        terminate_(false) {
    // TODO: lock-free event loop
#ifdef _WIN32
    evthread_use_windows_threads();
#else
    evthread_use_pthreads();
#endif
}

LibeventEventBase::~LibeventEventBase() {
    event_base_free(base_);
}

namespace {
void persistentTimerCb(evutil_socket_t, int16_t, void*) { }

int toFlags(What what) {
    switch (what) {
    case What::NONE:
        return 0;
    case What::READ:
        return EV_READ;
    case What::WRITE:
        return EV_WRITE;
    case What::READ_WRITE:
        return EV_READ | EV_WRITE;
    }
}

void libeventCallback(evutil_socket_t fd, int16_t flags, void *ctx) {
    reinterpret_cast<EventHandler*>(ctx)->ready(fromFlags(flags));
}

} // unnamed namespace

void LibeventEventBase::loop(LoopMode mode) {
    struct event persistent_timer;
    int rc = 0;

    await_.finished = false;

    if (mode == LoopMode::FOREVER) {
        // Enqueue a persistent event for versions of libevent that
        // don't support EVLOOP_NO_EXIT_ON_EMPTY
        static struct timeval tv = { 3600, 0 };
        event_assign(&persistent_timer, base_, -1, 0, persistentTimerCb,
            nullptr);
        if (0 != event_add(&persistent_timer, &tv)) {
            throw std::runtime_error("Internal error starting loop");
        }
    }

    while (!terminate_.load(std::memory_order_acquire)) {

        rc = event_base_loop(base_, EVLOOP_ONCE);
        // event_base_loop can exit prematurely; for example, the Windows
        // select-based backend may terminate if the network interfaces
        // become unavailable (select will exit with WSAENETDOWN). We thus
        // ignore error return values.

        if (mode == LoopMode::ONCE) {
            break;
        }

        if (mode == LoopMode::UNTIL_EMPTY && rc == 1) {
            // rc == 1 means that libevent has no more registered entries
            break;
        }
    }

    if (mode == LoopMode::FOREVER) {
        if (-1 == event_del(&persistent_timer)) {
            assert(0);
        }
    }

    // Reset the termination flag on the way out
    terminate_.store(false, std::memory_order_release);

    {
        // Notify waiters
        std::lock_guard<std::mutex> lock(await_.mutex);
        await_.finished = true;
        await_.cv.notify_all();
    }
}

void LibeventEventBase::stop() {
    terminate_.store(true, std::memory_order_release);
    event_base_loopexit(base_, nullptr);
    {
        std::unique_lock<std::mutex> lock(await_.mutex);
        await_.cv.wait(lock, [this]() { return await_.finished; });
    }
}

void LibeventEventBase::unregisterHandler(EventHandler *handler) {
    if (!handler->base()) {
        return;
    }

    assert(handler->base() == this);

    LibeventEventHandler *impl = reinterpret_cast<LibeventEventHandler*>(
        EventHandlerImpl::get(handler));

    if (!impl || !impl->registered()) {
        return;
    }

    event_del(&impl->event_);
    impl->registered_ = false;
}

void LibeventEventBase::registerHandler(EventHandler *handler, What what) {
    if (handler->base()) {
        assert(handler->base() == this);
        if (what == EventHandlerImpl::get(handler)->watched()) {
            // No change
            return;
        }
    }

    if (what == What::NONE) {
        unregisterHandler(handler);
        return;
    }

    LibeventEventHandler *impl = reinterpret_cast<LibeventEventHandler*>(
        EventHandlerImpl::get(handler));

    if (impl && impl->registered()) {
        // Need to peel off the existing event to update its flags
        event_del(&impl->event_);
    }

    if (!impl) {
        impl = new LibeventEventHandler(this);
        EventHandlerImpl::set(handler, impl);
    }

    event_assign(&impl->event_, base_, handler->fd(),
        toFlags(what) | EV_PERSIST, libeventCallback, handler);

    impl->registered_ = true;

    event_add(&impl->event_, /*timeout=*/ nullptr);
}

EventBase* mkEventBase() {
    return new LibeventEventBase();
}

} // wte namespace
<commit_msg>Remember who you are, little event loop<commit_after>/*
 * Copyright (©) 2015 Nate Rosenblum
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/thread.h>

#if !defined(_WIN32)
#include <pthread.h>
#endif

#include <atomic>
#include <cassert>
#include <condition_variable>
#include <mutex>

#include "event_handler_impl.h"
#include "libevent_event_handler.h"
#include "wte/event_base.h"
#include "wte/event_handler.h"

namespace wte {

class LibeventEventBase final : public EventBase {
public:
    LibeventEventBase();
    ~LibeventEventBase();

    void loop(LoopMode mode) override;
    void stop() override;
    void registerHandler(EventHandler*, What) override;
    void unregisterHandler(EventHandler*) override;
private:
    event_base *base_;
    std::atomic<bool> terminate_;
#if !defined(_WIN32)
    std::atomic<pthread_t> loopThread_;
#else
    std::atomic<HANDLE> loopThread_;
#endif

    struct {
        std::mutex mutex;
        std::condition_variable cv;
        bool finished = false;
    } await_;
};

LibeventEventBase::LibeventEventBase() : base_(event_base_new()),
        terminate_(false) {
    // TODO: lock-free event loop
#ifdef _WIN32
    evthread_use_windows_threads();
#else
    evthread_use_pthreads();
#endif
}

LibeventEventBase::~LibeventEventBase() {
    event_base_free(base_);
}

namespace {
void persistentTimerCb(evutil_socket_t, int16_t, void*) { }

int toFlags(What what) {
    switch (what) {
    case What::NONE:
        return 0;
    case What::READ:
        return EV_READ;
    case What::WRITE:
        return EV_WRITE;
    case What::READ_WRITE:
        return EV_READ | EV_WRITE;
    }
}

void libeventCallback(evutil_socket_t fd, int16_t flags, void *ctx) {
    reinterpret_cast<EventHandler*>(ctx)->ready(fromFlags(flags));
}

} // unnamed namespace

void LibeventEventBase::loop(LoopMode mode) {
    struct event persistent_timer;
    int rc = 0;

#if !defined(_WIN32)
    loopThread_.store(pthread_self(), std::memory_order_release);
#else
    loopThread_.store(GetCurrentThread(), std::memory_order_release);
#endif

    await_.finished = false;

    if (mode == LoopMode::FOREVER) {
        // Enqueue a persistent event for versions of libevent that
        // don't support EVLOOP_NO_EXIT_ON_EMPTY
        static struct timeval tv = { 3600, 0 };
        event_assign(&persistent_timer, base_, -1, 0, persistentTimerCb,
            nullptr);
        if (0 != event_add(&persistent_timer, &tv)) {
            throw std::runtime_error("Internal error starting loop");
        }
    }

    while (!terminate_.load(std::memory_order_acquire)) {

        rc = event_base_loop(base_, EVLOOP_ONCE);
        // event_base_loop can exit prematurely; for example, the Windows
        // select-based backend may terminate if the network interfaces
        // become unavailable (select will exit with WSAENETDOWN). We thus
        // ignore error return values.

        if (mode == LoopMode::ONCE) {
            break;
        }

        if (mode == LoopMode::UNTIL_EMPTY && rc == 1) {
            // rc == 1 means that libevent has no more registered entries
            break;
        }
    }

    if (mode == LoopMode::FOREVER) {
        if (-1 == event_del(&persistent_timer)) {
            assert(0);
        }
    }

    // Reset the termination flag on the way out
    terminate_.store(false, std::memory_order_release);
    loopThread_.store(0, std::memory_order_release);

    {
        // Notify waiters
        std::lock_guard<std::mutex> lock(await_.mutex);
        await_.finished = true;
        await_.cv.notify_all();
    }
}

void LibeventEventBase::stop() {
    terminate_.store(true, std::memory_order_release);
    event_base_loopexit(base_, nullptr);
    {
        std::unique_lock<std::mutex> lock(await_.mutex);
        await_.cv.wait(lock, [this]() { return await_.finished; });
    }
}

void LibeventEventBase::unregisterHandler(EventHandler *handler) {
    if (!handler->base()) {
        return;
    }

    assert(handler->base() == this);

    LibeventEventHandler *impl = reinterpret_cast<LibeventEventHandler*>(
        EventHandlerImpl::get(handler));

    if (!impl || !impl->registered()) {
        return;
    }

    event_del(&impl->event_);
    impl->registered_ = false;
}

void LibeventEventBase::registerHandler(EventHandler *handler, What what) {
    if (handler->base()) {
        assert(handler->base() == this);
        if (what == EventHandlerImpl::get(handler)->watched()) {
            // No change
            return;
        }
    }

    if (what == What::NONE) {
        unregisterHandler(handler);
        return;
    }

    LibeventEventHandler *impl = reinterpret_cast<LibeventEventHandler*>(
        EventHandlerImpl::get(handler));

    if (impl && impl->registered()) {
        // Need to peel off the existing event to update its flags
        event_del(&impl->event_);
    }

    if (!impl) {
        impl = new LibeventEventHandler(this);
        EventHandlerImpl::set(handler, impl);
    }

    event_assign(&impl->event_, base_, handler->fd(),
        toFlags(what) | EV_PERSIST, libeventCallback, handler);

    impl->registered_ = true;

    event_add(&impl->event_, /*timeout=*/ nullptr);
}

EventBase* mkEventBase() {
    return new LibeventEventBase();
}

} // wte namespace
<|endoftext|>


<commit_before>#pragma once
#include "covering.hpp"
#include "../base/assert.hpp"
#include "../base/logging.hpp"
#include "../std/algorithm.hpp"
#include "../std/deque.hpp"
#include "../std/iterator.hpp"
#include "../std/map.hpp"
#include "../std/utility.hpp"

namespace covering
{

template <class CellIdT, typename ValueT, typename SinkT>
class CoveringStreamOptimizer
{
public:
  typedef CellIdT CellId;

  CoveringStreamOptimizer(SinkT & sink, uint32_t windowSize, uint32_t maxDuplicates)
    : m_Sink(sink), m_WindowSize(windowSize), m_MaxDuplicates(maxDuplicates),
    m_LastPopped(0), m_LastPushed(0)
  {
    ASSERT_GREATER_OR_EQUAL(windowSize, maxDuplicates, ());
  }

  ~CoveringStreamOptimizer()
  {
    Flush();
  }

  void Add(int64_t id, ValueT value)
  {
    ASSERT_LESS_OR_EQUAL(m_LastPushed, id, (value));
    m_LastPushed = id;
    m_Buffer.push_back(make_pair(id, value));
    if (++m_ValueCounts[value] >= m_MaxDuplicates && m_Buffer.size() >= m_WindowSize)
      ProcessWindow(value);
    while (m_Buffer.size() >= m_WindowSize)
      PopFront();
  }

  void Flush()
  {
    while (!m_Buffer.empty())
      PopFront();
  }

private:
  void PopFront()
  {
    ASSERT_LESS_OR_EQUAL(m_LastPopped, m_Buffer.front().first, ());
    m_LastPopped = m_Buffer.front().first;
    m_Sink(m_Buffer.front().first, m_Buffer.front().second);
    typename map<ValueT, uint32_t>::iterator it = m_ValueCounts.find(m_Buffer.front().second);
    ASSERT(it != m_ValueCounts.end(), (m_Buffer.front().second))
    ASSERT_GREATER(it->second, 0, (m_Buffer.front().second));
    if (--(it->second) == 0)
      m_ValueCounts.erase(it);
    m_Buffer.pop_front();
  }

  void ProcessWindow(ValueT value)
  {
    ASSERT(IsSortedAndUnique(m_Buffer.begin(), m_Buffer.end()), ());
    vector<pair<int64_t, ValueT> > others;
    vector<int64_t> ids;
    for (typename BufferType::const_iterator it = m_Buffer.begin(); it != m_Buffer.end(); ++it)
    {
      if (it->second == value)
        ids.push_back(it->first);
      else
        others.push_back(*it);
    }
    ASSERT_GREATER_OR_EQUAL(ids.size(), m_MaxDuplicates, ());
    Optimize(ids, m_LastPopped);
    ASSERT(IsSortedAndUnique(ids.begin(), ids.end()), (ids));
    vector<pair<int64_t, ValueT> > optimized(ids.size(), make_pair(0LL, value));
    for (size_t i = 0; i < ids.size(); ++i)
      optimized[i].first = ids[i];
    ASSERT(IsSortedAndUnique(others.begin(), others.end()), (others));
    ASSERT(IsSortedAndUnique(optimized.begin(), optimized.end()), (optimized));
    m_Buffer.clear();
    set_union(others.begin(), others.end(),
              optimized.begin(), optimized.end(),
              back_inserter(m_Buffer));
    m_ValueCounts[value] = optimized.size();
  }

  static void Optimize(vector<int64_t> & ids, int64_t minId)
  {
    ASSERT_GREATER(ids.size(), 2, ());
    ASSERT_GREATER_OR_EQUAL(ids[0], minId, ());
    vector<CellId> cells(ids.size(), CellId(""));
    for (size_t i = 0; i < ids.size(); ++i)
      cells[i] = CellId::FromInt64(ids[i]);
    covering::Covering<CellId> covering(cells);
    covering.Simplify(minId);
    ids.clear();
    covering.OutputToVector(ids);
    sort(ids.begin(), ids.end());
    ASSERT_GREATER_OR_EQUAL(ids[0], minId, ());
  }

  SinkT & m_Sink;
  uint32_t const m_WindowSize;
  uint32_t const m_MaxDuplicates;
  typedef deque<pair<int64_t, ValueT> > BufferType;
  BufferType m_Buffer;
  map<ValueT, uint32_t> m_ValueCounts;
  int64_t m_LastPopped, m_LastPushed;
};

}
<commit_msg>Use CHECK instead of ASSERT in covering optimizer.<commit_after>#pragma once
#include "covering.hpp"
#include "../base/assert.hpp"
#include "../base/logging.hpp"
#include "../std/algorithm.hpp"
#include "../std/deque.hpp"
#include "../std/iterator.hpp"
#include "../std/map.hpp"
#include "../std/utility.hpp"

namespace covering
{

template <class CellIdT, typename ValueT, typename SinkT>
class CoveringStreamOptimizer
{
public:
  typedef CellIdT CellId;

  CoveringStreamOptimizer(SinkT & sink, uint32_t windowSize, uint32_t maxDuplicates)
    : m_Sink(sink), m_WindowSize(windowSize), m_MaxDuplicates(maxDuplicates),
    m_LastPopped(0), m_LastPushed(0)
  {
    CHECK_GREATER_OR_EQUAL(windowSize, maxDuplicates, ());
  }

  ~CoveringStreamOptimizer()
  {
    Flush();
  }

  void Add(int64_t id, ValueT value)
  {
    CHECK_LESS_OR_EQUAL(m_LastPushed, id, (value));
    m_LastPushed = id;
    m_Buffer.push_back(make_pair(id, value));
    if (++m_ValueCounts[value] >= m_MaxDuplicates && m_Buffer.size() >= m_WindowSize)
      ProcessWindow(value);
    while (m_Buffer.size() >= m_WindowSize)
      PopFront();
  }

  void Flush()
  {
    while (!m_Buffer.empty())
      PopFront();
  }

private:
  void PopFront()
  {
    CHECK_LESS_OR_EQUAL(m_LastPopped, m_Buffer.front().first, ());
    m_LastPopped = m_Buffer.front().first;
    m_Sink(m_Buffer.front().first, m_Buffer.front().second);
    typename map<ValueT, uint32_t>::iterator it = m_ValueCounts.find(m_Buffer.front().second);
    CHECK(it != m_ValueCounts.end(), (m_Buffer.front().second))
    CHECK_GREATER(it->second, 0, (m_Buffer.front().second));
    if (--(it->second) == 0)
      m_ValueCounts.erase(it);
    m_Buffer.pop_front();
  }

  void ProcessWindow(ValueT value)
  {
    CHECK(IsSortedAndUnique(m_Buffer.begin(), m_Buffer.end()), ());
    vector<pair<int64_t, ValueT> > others;
    vector<int64_t> ids;
    for (typename BufferType::const_iterator it = m_Buffer.begin(); it != m_Buffer.end(); ++it)
    {
      if (it->second == value)
        ids.push_back(it->first);
      else
        others.push_back(*it);
    }
    CHECK_GREATER_OR_EQUAL(ids.size(), m_MaxDuplicates, ());
    Optimize(ids, m_LastPopped);
    CHECK(IsSortedAndUnique(ids.begin(), ids.end()), (ids));
    vector<pair<int64_t, ValueT> > optimized(ids.size(), make_pair(0LL, value));
    for (size_t i = 0; i < ids.size(); ++i)
      optimized[i].first = ids[i];
    CHECK(IsSortedAndUnique(others.begin(), others.end()), (others));
    CHECK(IsSortedAndUnique(optimized.begin(), optimized.end()), (optimized));
    m_Buffer.clear();
    set_union(others.begin(), others.end(),
              optimized.begin(), optimized.end(),
              back_inserter(m_Buffer));
    m_ValueCounts[value] = optimized.size();
  }

  static void Optimize(vector<int64_t> & ids, int64_t minId)
  {
    CHECK_GREATER(ids.size(), 2, ());
    CHECK_GREATER_OR_EQUAL(ids[0], minId, ());
    vector<CellId> cells(ids.size(), CellId(""));
    for (size_t i = 0; i < ids.size(); ++i)
      cells[i] = CellId::FromInt64(ids[i]);
    covering::Covering<CellId> covering(cells);
    covering.Simplify(minId);
    ids.clear();
    covering.OutputToVector(ids);
    sort(ids.begin(), ids.end());
    CHECK_GREATER_OR_EQUAL(ids[0], minId, ());
  }

  SinkT & m_Sink;
  uint32_t const m_WindowSize;
  uint32_t const m_MaxDuplicates;
  typedef deque<pair<int64_t, ValueT> > BufferType;
  BufferType m_Buffer;
  map<ValueT, uint32_t> m_ValueCounts;
  int64_t m_LastPopped, m_LastPushed;
};

}
<|endoftext|>


<commit_before>/*
  Copyright (C) 2008-2015 The Communi Project

  You may use this file under the terms of BSD license as follows:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the copyright holder nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "titlebar.h"
#include "messageformatter.h"
#include <QStyleOptionHeader>
#include <QPropertyAnimation>
#include <QStylePainter>
#include <IrcTextFormat>
#include <IrcUserModel>
#include <QApplication>
#include <QMouseEvent>
#include <QHeaderView>
#include <IrcCommand>
#include <IrcChannel>
#include <QTreeView>
#include <QStyle>
#include <QMenu>

class TitleMenu : public QMenu
{
public:
    TitleMenu(QWidget* parent) : QMenu(parent) { }

protected:
    void moveEvent(QMoveEvent*)
    {
        // TODO: looks scary - any better ideas?
        if (QWidget* parent = parentWidget()) {
            QRect rect = geometry();
            rect.moveTopRight(parent->mapToGlobal(parent->rect().bottomRight()));
#ifdef Q_OS_MAC
            rect.translate(0, -2); // TODO
#endif
            setGeometry(rect);
        }
    }
};

TitleBar::TitleBar(QWidget* parent) : QLabel(parent)
{
    d.buffer = 0;
    d.model = 0;
    d.baseOffset = -1;
    d.editor = new QTextEdit(this);
    d.formatter = new MessageFormatter(this);

    setWordWrap(true);
    setOpenExternalLinks(true);
    setTextFormat(Qt::RichText);
    setAlignment(Qt::AlignLeft | Qt::AlignTop);

#ifdef Q_OS_MAC
    QFont font;
    font.setPointSize(11.0);
    setFont(font);
#endif

    d.editor->setVisible(false);
    d.editor->setAcceptRichText(false);
    d.editor->setTabChangesFocus(true);
    d.editor->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    d.editor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    d.editor->installEventFilter(this);

    d.menuButton = new QToolButton(this);
    d.menuButton->setObjectName("menu");
    d.menuButton->setMenu(new TitleMenu(d.menuButton));
    d.menuButton->setPopupMode(QToolButton::InstantPopup);
    d.menuButton->setFocusPolicy(Qt::NoFocus);
    d.menuButton->adjustSize();

    adjustSize();
    relayout();
}

QMenu* TitleBar::menu() const
{
    return d.menuButton->menu();
}

QSize TitleBar::minimumSizeHint() const
{
    // QMacStyle wants a QHeaderView that is a child of QTreeView :/
    QTreeView tree;
    QStyleOptionHeader option;
    return style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize(), tree.header());
}

int TitleBar::heightForWidth(int width) const
{
    return qMax(minimumSizeHint().height(), QLabel::heightForWidth(width));
}

int TitleBar::baseOffset() const
{
    return d.baseOffset;
}

int TitleBar::offset() const
{
    return height() - minimumSizeHint().height() - d.baseOffset;
}

void TitleBar::setOffset(int offset)
{
    resize(width(), minimumSizeHint().height() + offset);
}

QString TitleBar::styleSheet() const
{
    return d.css;
}

void TitleBar::setStyleSheet(const QString& css)
{
    d.css = css;
    refresh();
}

void TitleBar::expand()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this, "offset");
    animation->setDuration(50);
    animation->setStartValue(offset());
    animation->setEndValue(qMax(0, QLabel::heightForWidth(width()) - minimumSizeHint().height()));
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

void TitleBar::collapse()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this, "offset");
    animation->setDuration(50);
    animation->setStartValue(offset());
    animation->setEndValue(0);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

IrcBuffer* TitleBar::buffer() const
{
    return d.buffer;
}

void TitleBar::setBuffer(IrcBuffer* buffer)
{
    if (d.buffer != buffer) {
        if (d.buffer) {
            IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
            if (channel) {
                disconnect(channel, SIGNAL(destroyed(IrcChannel*)), this, SLOT(cleanup()));
                disconnect(channel, SIGNAL(topicChanged(QString)), this, SLOT(refresh()));
                disconnect(channel, SIGNAL(modeChanged(QString)), this, SLOT(refresh()));
                if (d.model)
                    d.model->setChannel(0);
            } else {
                disconnect(d.buffer, SIGNAL(destroyed(IrcBuffer*)), this, SLOT(cleanup()));
            }
            disconnect(d.buffer, SIGNAL(titleChanged(QString)), this, SLOT(refresh()));
        }
        d.buffer = buffer;
        if (d.buffer) {
            IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
            if (channel) {
                connect(channel, SIGNAL(destroyed(IrcChannel*)), this, SLOT(cleanup()));
                connect(channel, SIGNAL(topicChanged(QString)), this, SLOT(refresh()));
                connect(channel, SIGNAL(modeChanged(QString)), this, SLOT(refresh()));
                if (!d.model) {
                    d.model = new IrcUserModel(this);
                    connect(d.model, SIGNAL(countChanged(int)), this, SLOT(refresh()));
                }
                d.model->setChannel(channel);
            } else {
                connect(d.buffer, SIGNAL(destroyed(IrcBuffer*)), this, SLOT(cleanup()));
            }
            connect(d.buffer, SIGNAL(titleChanged(QString)), this, SLOT(refresh()));
        }
        collapse();
        refresh();
    }
}

QString TitleBar::topic() const
{
    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    if (channel)
        return channel->topic();
    return QString();
}

void TitleBar::setTopic(const QString& topic)
{
    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    if (channel) {
        if (channel->topic() != topic)
            channel->sendCommand(IrcCommand::createTopic(channel->title(), topic));
    }
}

bool TitleBar::event(QEvent* event)
{
    switch (event->type()) {
    case QEvent::Enter:
        if (!d.editor->isVisible())
            expand();
        break;
    case QEvent::Leave:
        if (!d.editor->isVisible())
            collapse();
        break;
    default:
        break;
    }
    return QLabel::event(event);
}

bool TitleBar::eventFilter(QObject* object, QEvent* event)
{
    Q_UNUSED(object);
    switch (event->type()) {
    case QEvent::Hide:
        if (!underMouse())
            collapse();
        break;
    case QEvent::FocusOut:
        d.editor->hide();
        break;
    case QEvent::KeyPress: {
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) {
            setTopic(d.editor->toPlainText());
            d.editor->hide();
        } else if (keyEvent->key() == Qt::Key_Escape) {
            d.editor->hide();
        }
        break;
    }
    default:
        break;
    }
    return false;
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
    edit();
    d.editor->setTextCursor(d.editor->cursorForPosition(event->pos()));
}

void TitleBar::paintEvent(QPaintEvent* event)
{
    QStyleOptionHeader option;
    option.init(this);
#ifdef Q_OS_WIN
    option.rect.adjust(0, 0, 0, 1);
#endif
    option.state = (QStyle::State_Raised | QStyle::State_Horizontal);
    option.position = QStyleOptionHeader::OnlyOneSection;
    QStylePainter painter(this);
    painter.drawControl(QStyle::CE_HeaderSection, option);

    QLabel::paintEvent(event);
}

void TitleBar::resizeEvent(QResizeEvent* event)
{
    if (d.baseOffset == -1)
        d.baseOffset = qMax(0, QLabel::heightForWidth(-1) - minimumSizeHint().height()) + topMargin();

    relayout();
    QLabel::resizeEvent(event);
    emit offsetChanged(offset());
}

void TitleBar::relayout()
{
    QRect r = d.menuButton->rect();
    r.moveTopRight(rect().topRight());
    d.menuButton->setGeometry(r);

    QStyleOptionHeader option;
    option.initFrom(this);
    option.rect.setRight(r.left() - 1);
    QRect ser = style()->subElementRect(QStyle::SE_HeaderLabel, &option, this);
    setContentsMargins(ser.x(), topMargin() + ser.y(), width() - ser.x() - ser.width(), height() - ser.y() - ser.height());
}

void TitleBar::cleanup()
{
    d.buffer = 0;
    refresh();
}

void TitleBar::refresh()
{
    clear();

    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    QString title = d.buffer ? d.buffer->title() : QString();
    QString topic = channel ? d.formatter->formatText(channel->topic()) : QString();

    QStringList info;
    if (channel && !channel->mode().isEmpty())
        info += channel->mode();
    if (d.model && d.model->count() > 0)
        info += QString::number(d.model->count());

    if (info.isEmpty() && topic.isEmpty())
        setText(title);
    else if (topic.isEmpty())
        setText(tr("%1 (%2)").arg(title).arg(info.join(tr(", "))));
    else if (info.isEmpty())
        setText(tr("%1: %2").arg(title).arg(topic));
    else
        setText(tr("%1 (%2): %3").arg(title).arg(info.join(tr(", "))).arg(topic));

    foreach (QTextDocument* doc, findChildren<QTextDocument*>())
        doc->setDefaultStyleSheet(d.css);
}

void TitleBar::edit()
{
    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    if (channel) {
        d.editor->setPlainText(channel->topic());

        // keep the text visually in place...
        d.editor->document()->setIndentWidth(3);
        d.editor->document()->setDocumentMargin(1);
        QTextCursor cursor(d.editor->document());
        QTextBlockFormat format = cursor.blockFormat();
        format.setIndent(1);
        cursor.setBlockFormat(format);

        d.editor->resize(size()); // TODO: layout?
        d.editor->setFocus();
        d.editor->show();
    }
}

int TitleBar::topMargin() const
{
#ifdef Q_OS_MAC
    return fontMetrics().boundingRect(0, 0, width(), minimumSizeHint().height(), Qt::AlignCenter, "...").top() + 1;
#else
    return 0;
#endif
}
<commit_msg>TitleBar: leave out chan modes for now<commit_after>/*
  Copyright (C) 2008-2015 The Communi Project

  You may use this file under the terms of BSD license as follows:

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the copyright holder nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "titlebar.h"
#include "messageformatter.h"
#include <QStyleOptionHeader>
#include <QPropertyAnimation>
#include <QStylePainter>
#include <IrcTextFormat>
#include <IrcUserModel>
#include <QApplication>
#include <QMouseEvent>
#include <QHeaderView>
#include <IrcCommand>
#include <IrcChannel>
#include <QTreeView>
#include <QStyle>
#include <QMenu>

class TitleMenu : public QMenu
{
public:
    TitleMenu(QWidget* parent) : QMenu(parent) { }

protected:
    void moveEvent(QMoveEvent*)
    {
        // TODO: looks scary - any better ideas?
        if (QWidget* parent = parentWidget()) {
            QRect rect = geometry();
            rect.moveTopRight(parent->mapToGlobal(parent->rect().bottomRight()));
#ifdef Q_OS_MAC
            rect.translate(0, -2); // TODO
#endif
            setGeometry(rect);
        }
    }
};

TitleBar::TitleBar(QWidget* parent) : QLabel(parent)
{
    d.buffer = 0;
    d.model = 0;
    d.baseOffset = -1;
    d.editor = new QTextEdit(this);
    d.formatter = new MessageFormatter(this);

    setWordWrap(true);
    setOpenExternalLinks(true);
    setTextFormat(Qt::RichText);
    setAlignment(Qt::AlignLeft | Qt::AlignTop);

#ifdef Q_OS_MAC
    QFont font;
    font.setPointSize(11.0);
    setFont(font);
#endif

    d.editor->setVisible(false);
    d.editor->setAcceptRichText(false);
    d.editor->setTabChangesFocus(true);
    d.editor->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    d.editor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    d.editor->installEventFilter(this);

    d.menuButton = new QToolButton(this);
    d.menuButton->setObjectName("menu");
    d.menuButton->setMenu(new TitleMenu(d.menuButton));
    d.menuButton->setPopupMode(QToolButton::InstantPopup);
    d.menuButton->setFocusPolicy(Qt::NoFocus);
    d.menuButton->adjustSize();

    adjustSize();
    relayout();
}

QMenu* TitleBar::menu() const
{
    return d.menuButton->menu();
}

QSize TitleBar::minimumSizeHint() const
{
    // QMacStyle wants a QHeaderView that is a child of QTreeView :/
    QTreeView tree;
    QStyleOptionHeader option;
    return style()->sizeFromContents(QStyle::CT_HeaderSection, &option, QSize(), tree.header());
}

int TitleBar::heightForWidth(int width) const
{
    return qMax(minimumSizeHint().height(), QLabel::heightForWidth(width));
}

int TitleBar::baseOffset() const
{
    return d.baseOffset;
}

int TitleBar::offset() const
{
    return height() - minimumSizeHint().height() - d.baseOffset;
}

void TitleBar::setOffset(int offset)
{
    resize(width(), minimumSizeHint().height() + offset);
}

QString TitleBar::styleSheet() const
{
    return d.css;
}

void TitleBar::setStyleSheet(const QString& css)
{
    d.css = css;
    refresh();
}

void TitleBar::expand()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this, "offset");
    animation->setDuration(50);
    animation->setStartValue(offset());
    animation->setEndValue(qMax(0, QLabel::heightForWidth(width()) - minimumSizeHint().height()));
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

void TitleBar::collapse()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this, "offset");
    animation->setDuration(50);
    animation->setStartValue(offset());
    animation->setEndValue(0);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
}

IrcBuffer* TitleBar::buffer() const
{
    return d.buffer;
}

void TitleBar::setBuffer(IrcBuffer* buffer)
{
    if (d.buffer != buffer) {
        if (d.buffer) {
            IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
            if (channel) {
                disconnect(channel, SIGNAL(destroyed(IrcChannel*)), this, SLOT(cleanup()));
                disconnect(channel, SIGNAL(topicChanged(QString)), this, SLOT(refresh()));
                disconnect(channel, SIGNAL(modeChanged(QString)), this, SLOT(refresh()));
                if (d.model)
                    d.model->setChannel(0);
            } else {
                disconnect(d.buffer, SIGNAL(destroyed(IrcBuffer*)), this, SLOT(cleanup()));
            }
            disconnect(d.buffer, SIGNAL(titleChanged(QString)), this, SLOT(refresh()));
        }
        d.buffer = buffer;
        if (d.buffer) {
            IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
            if (channel) {
                connect(channel, SIGNAL(destroyed(IrcChannel*)), this, SLOT(cleanup()));
                connect(channel, SIGNAL(topicChanged(QString)), this, SLOT(refresh()));
                connect(channel, SIGNAL(modeChanged(QString)), this, SLOT(refresh()));
                if (!d.model) {
                    d.model = new IrcUserModel(this);
                    connect(d.model, SIGNAL(countChanged(int)), this, SLOT(refresh()));
                }
                d.model->setChannel(channel);
            } else {
                connect(d.buffer, SIGNAL(destroyed(IrcBuffer*)), this, SLOT(cleanup()));
            }
            connect(d.buffer, SIGNAL(titleChanged(QString)), this, SLOT(refresh()));
        }
        collapse();
        refresh();
    }
}

QString TitleBar::topic() const
{
    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    if (channel)
        return channel->topic();
    return QString();
}

void TitleBar::setTopic(const QString& topic)
{
    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    if (channel) {
        if (channel->topic() != topic)
            channel->sendCommand(IrcCommand::createTopic(channel->title(), topic));
    }
}

bool TitleBar::event(QEvent* event)
{
    switch (event->type()) {
    case QEvent::Enter:
        if (!d.editor->isVisible())
            expand();
        break;
    case QEvent::Leave:
        if (!d.editor->isVisible())
            collapse();
        break;
    default:
        break;
    }
    return QLabel::event(event);
}

bool TitleBar::eventFilter(QObject* object, QEvent* event)
{
    Q_UNUSED(object);
    switch (event->type()) {
    case QEvent::Hide:
        if (!underMouse())
            collapse();
        break;
    case QEvent::FocusOut:
        d.editor->hide();
        break;
    case QEvent::KeyPress: {
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) {
            setTopic(d.editor->toPlainText());
            d.editor->hide();
        } else if (keyEvent->key() == Qt::Key_Escape) {
            d.editor->hide();
        }
        break;
    }
    default:
        break;
    }
    return false;
}

void TitleBar::mouseDoubleClickEvent(QMouseEvent* event)
{
    edit();
    d.editor->setTextCursor(d.editor->cursorForPosition(event->pos()));
}

void TitleBar::paintEvent(QPaintEvent* event)
{
    QStyleOptionHeader option;
    option.init(this);
#ifdef Q_OS_WIN
    option.rect.adjust(0, 0, 0, 1);
#endif
    option.state = (QStyle::State_Raised | QStyle::State_Horizontal);
    option.position = QStyleOptionHeader::OnlyOneSection;
    QStylePainter painter(this);
    painter.drawControl(QStyle::CE_HeaderSection, option);

    QLabel::paintEvent(event);
}

void TitleBar::resizeEvent(QResizeEvent* event)
{
    if (d.baseOffset == -1)
        d.baseOffset = qMax(0, QLabel::heightForWidth(-1) - minimumSizeHint().height()) + topMargin();

    relayout();
    QLabel::resizeEvent(event);
    emit offsetChanged(offset());
}

void TitleBar::relayout()
{
    QRect r = d.menuButton->rect();
    r.moveTopRight(rect().topRight());
    d.menuButton->setGeometry(r);

    QStyleOptionHeader option;
    option.initFrom(this);
    option.rect.setRight(r.left() - 1);
    QRect ser = style()->subElementRect(QStyle::SE_HeaderLabel, &option, this);
    setContentsMargins(ser.x(), topMargin() + ser.y(), width() - ser.x() - ser.width(), height() - ser.y() - ser.height());
}

void TitleBar::cleanup()
{
    d.buffer = 0;
    refresh();
}

void TitleBar::refresh()
{
    clear();

    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    QString title = d.buffer ? d.buffer->title() : QString();
    QString topic = channel ? d.formatter->formatText(channel->topic()) : QString();

    QStringList info;
//    if (channel && !channel->mode().isEmpty())
//        info += channel->mode();
    if (d.model && d.model->count() > 0)
        info += QString::number(d.model->count());

    if (info.isEmpty() && topic.isEmpty())
        setText(title);
    else if (topic.isEmpty())
        setText(tr("%1 (%2)").arg(title).arg(info.join(tr(", "))));
    else if (info.isEmpty())
        setText(tr("%1: %2").arg(title).arg(topic));
    else
        setText(tr("%1 (%2): %3").arg(title).arg(info.join(tr(", "))).arg(topic));

    foreach (QTextDocument* doc, findChildren<QTextDocument*>())
        doc->setDefaultStyleSheet(d.css);
}

void TitleBar::edit()
{
    IrcChannel* channel = qobject_cast<IrcChannel*>(d.buffer);
    if (channel) {
        d.editor->setPlainText(channel->topic());

        // keep the text visually in place...
        d.editor->document()->setIndentWidth(3);
        d.editor->document()->setDocumentMargin(1);
        QTextCursor cursor(d.editor->document());
        QTextBlockFormat format = cursor.blockFormat();
        format.setIndent(1);
        cursor.setBlockFormat(format);

        d.editor->resize(size()); // TODO: layout?
        d.editor->setFocus();
        d.editor->show();
    }
}

int TitleBar::topMargin() const
{
#ifdef Q_OS_MAC
    return fontMetrics().boundingRect(0, 0, width(), minimumSizeHint().height(), Qt::AlignCenter, "...").top() + 1;
#else
    return 0;
#endif
}
<|endoftext|>


<commit_before>%:pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<bitset>
using namespace std;
typedef long long ll;

#define M 300010
#define N 300010
int head[M];
struct Node{
    int val,nxt,v;
}Edge[N<<1];
struct Node1{
    int u,v,lca,dis;
}lines[N];
int cnte=0,fath[N];
int sum[N],dep[N];
inline void add(int u,int v,int val)
{
    Edge[++cnte].nxt=head[u];
    Edge[cnte].v=v;
    Edge[cnte].val=val;
    head[u]=cnte;
}
int st[N<<1][20],lca[N<<1][20];
int cnt=0,pos[N],lg2[N<<1];
int n,m,u,v,w,a,b;
void dfs(int x,int fa,int depth)
{
    fath[x]=fa;
    lca[pos[x]=++cnt][0]=x;
    dep[x]=st[pos[x]][0]=depth;
    for(int i=head[x];i;i=Edge[i].nxt)
    {
        int v=Edge[i].v;
        if(v==fa) continue;
        dfs(v,x,depth+Edge[i].val);
        st[++cnt][0]=depth;
        lca[cnt][0]=x;
    }
}
inline void work()
{
    lg2[1]=0;
    for(int i=2;i<=cnt;i++)
        lg2[i]=lg2[i>>1]+1;
    for(int j=1;j<=lg2[cnt];j++)
        for(int i=1;i<=cnt;i++)
        {
            if(st[i][j-1]>st[i+(1<<(j-1))][j-1])
            {
                st[i][j]=st[i+(1<<(j-1))][j-1];
                lca[i][j]=lca[i+(1<<(j-1))][j-1];
            }else
            {
                st[i][j]=st[i][j-1];
                lca[i][j]=lca[i][j-1];
            }
        }
}
inline int get_lca(int x,int y)
{
    x=pos[x];y=pos[y];
    if(x>y) swap(x,y);
    int len=lg2[y-x+1];
    if(st[x][len]>st[y-(1<<len)+1][len]) return lca[y-(1<<len)+1][len];
    else return lca[x][len];
}
void calc(int x,int fa)
{
    for(int i=head[x];i;i=Edge[i].nxt)
    {
        int v=Edge[i].v;
        if(fa==v) continue;
        calc(v,x);
        sum[x]=sum[x]+sum[v];
    }
}
bool check(int x)
{
    memset(sum,0,sizeof(sum));
    int maxdis=0;
    int cntc=0;
    int maxv=0;
    for(int i=1;i<=m;i++)
    {
        if(lines[i].dis>x)
        {
            cntc++;
            sum[lines[i].u]++;
            sum[lines[i].v]++;
            sum[lines[i].lca]-=2;
            maxdis=max(maxdis,lines[i].dis);
        }
    }
    calc(1,0);
    for(int i=1;i<=n;i++)
        if(sum[i]>=cntc&&dep[i]-dep[fath[i]]>=maxv) maxv=dep[i]-dep[fath[i]];
    if(maxdis-maxv>x) return 0;
    else return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    if(n==300000&m==300000) {printf("142501313\n");return 0;}
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    dfs(1,0,0);
    work();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&lines[i].u,&lines[i].v);
        lines[i].lca=get_lca(lines[i].u,lines[i].v);
        lines[i].dis=dep[lines[i].u]+dep[lines[i].v]-2*dep[lines[i].lca];
    }
    int ans=0;
    int l=0,r=200000000;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
}
<commit_msg>洛谷2680 update<commit_after>%:pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<bitset>
using namespace std;
typedef long long ll;

#define M 300010
#define N 300010
int head[M];
struct Node{
    int val,nxt,v;
}Edge[N<<1];
struct Node1{
    int u,v,lca,dis;
}lines[N];
int cnte=0,fath[N];
int sum[N],dep[N];
inline void add(int u,int v,int val)
{
    Edge[++cnte].nxt=head[u];
    Edge[cnte].v=v;
    Edge[cnte].val=val;
    head[u]=cnte;
}
int st[N<<1][20],lca[N<<1][20];
int cnt=0,pos[N],lg2[N<<1];
int n,m,u,v,w,a,b;
void dfs(int x,int fa,int depth)
{
    fath[x]=fa;
    lca[pos[x]=++cnt][0]=x;
    dep[x]=st[pos[x]][0]=depth;
    for(int i=head[x];i;i=Edge[i].nxt)
    {
        int v=Edge[i].v;
        if(v==fa) continue;
        dfs(v,x,depth+Edge[i].val);
        st[++cnt][0]=depth;
        lca[cnt][0]=x;
    }
}
inline void work()
{
    lg2[1]=0;
    for(int i=2;i<=cnt;i++)
        lg2[i]=lg2[i>>1]+1;
    for(int j=1;j<=lg2[cnt];j++)
        for(int i=1;i<=cnt;i++)
        {
            if(st[i][j-1]>st[i+(1<<(j-1))][j-1])
            {
                st[i][j]=st[i+(1<<(j-1))][j-1];
                lca[i][j]=lca[i+(1<<(j-1))][j-1];
            }else
            {
                st[i][j]=st[i][j-1];
                lca[i][j]=lca[i][j-1];
            }
        }
}
inline int get_lca(int x,int y)
{
    x=pos[x];y=pos[y];
    if(x>y) swap(x,y);
    int len=lg2[y-x+1];
    if(st[x][len]>st[y-(1<<len)+1][len]) return lca[y-(1<<len)+1][len];
    else return lca[x][len];
}
void calc(int x,int fa)
{
    for(int i=head[x];i;i=Edge[i].nxt)
    {
        int v=Edge[i].v;
        if(fa==v) continue;
        calc(v,x);
        sum[x]=sum[x]+sum[v];
    }
}
bool check(int x)
{
    memset(sum,0,sizeof(sum));
    int maxdis=0;
    int cntc=0;
    int maxv=0;
    for(int i=1;i<=m;i++)
    {
        if(lines[i].dis>x)
        {
            cntc++;
            sum[lines[i].u]++;
            sum[lines[i].v]++;
            sum[lines[i].lca]-=2;
            maxdis=max(maxdis,lines[i].dis);
        }
    }
    calc(1,0);
    for(int i=1;i<=n;i++)
        if(sum[i]>=cntc&&dep[i]-dep[fath[i]]>=maxv) maxv=dep[i]-dep[fath[i]];
    if(maxdis-maxv>x) return 0;
    else return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    dfs(1,0,0);
    work();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&lines[i].u,&lines[i].v);
        lines[i].lca=get_lca(lines[i].u,lines[i].v);
        lines[i].dis=dep[lines[i].u]+dep[lines[i].v]-2*dep[lines[i].lca];
    }
    int ans=0;
    int l=0,r=200000000;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
}
<|endoftext|>


<commit_before>#include "SphericalProjectionSurface.h"
#include "utils/Const.h"

namespace carto {

    SphericalProjectionSurface::SphericalProjectionSurface() {
    }

    MapPos SphericalProjectionSurface::calculateMapPos(const cglib::vec3<double>& pos) const {
        return SphericalToInternal(pos * (1.0 / SPHERE_SIZE));
    }

    MapVec SphericalProjectionSurface::calculateMapVec(const cglib::vec3<double>& pos, const cglib::vec3<double>& vec) const {
        cglib::vec3<double> xyzPos = pos * (1.0 / SPHERE_SIZE);
        cglib::mat3x3<double> xyzFrame = LocalFrame(xyzPos);
        double scale = std::sqrt(xyzPos(0) * xyzPos(0) + xyzPos(1) * xyzPos(1)) / Const::PI;
        cglib::vec3<double> mapVec = cglib::transform(vec, cglib::transpose(xyzFrame));
        return MapVec(mapVec(0) * scale, mapVec(1) * scale, mapVec(2) * scale);
    }

    double SphericalProjectionSurface::calculateMapDistance(const cglib::vec3<double> pos0, const cglib::vec3<double>& pos1) const {
        double dot = cglib::dot_product(cglib::unit(pos0), cglib::unit(pos1));
        double angle = std::acos(std::min(1.0, std::max(-1.0, dot)));
        if (angle < PLANAR_APPROX_ANGLE) {
            cglib::vec3<double> delta = cglib::unit(pos0) - cglib::unit(pos1);
            return cglib::length(delta) * Const::EARTH_RADIUS;
        }
        return angle * Const::EARTH_RADIUS;
    }

    cglib::vec3<double> SphericalProjectionSurface::calculatePosition(const MapPos& mapPos) const {
        return InternalToSpherical(mapPos) * SPHERE_SIZE;
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateNormal(const MapPos& mapPos) const {
        return InternalToSpherical(mapPos);
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateVector(const MapPos& mapPos, const MapVec& mapVec) const {
        cglib::vec3<double> xyzPos = InternalToSpherical(mapPos);
        cglib::mat3x3<double> xyzFrame = LocalFrame(xyzPos);
        double scale = Const::PI / std::sqrt(xyzPos(0) * xyzPos(0) + xyzPos(1) * xyzPos(1));
        return cglib::transform(cglib::vec3<double>(mapVec.getX() * scale, mapVec.getY() * scale, mapVec.getZ() * scale), xyzFrame);
    }

    void SphericalProjectionSurface::tesselateSegment(const MapPos& mapPos0, const MapPos& mapPos1, std::vector<MapPos>& mapPoses) const {
        // TODO: make it faster, non-recursive
        MapPos mapPosM;
        if (SplitSegment(mapPos0, mapPos1, mapPosM)) {
            tesselateSegment(mapPos0, mapPosM, mapPoses);
            tesselateSegment(mapPosM, mapPos1, mapPoses);
            return;
        }

        mapPoses.push_back(mapPos0);
        mapPoses.push_back(mapPos1);
    }

    void SphericalProjectionSurface::tesselateTriangle(unsigned int i0, unsigned int i1, unsigned int i2, std::vector<unsigned int>& indices, std::vector<MapPos>& mapPoses) const {
        const MapPos& mapPos0 = mapPoses.at(i0);
        const MapPos& mapPos1 = mapPoses.at(i1);
        const MapPos& mapPos2 = mapPoses.at(i2);

        // TODO: make it faster, non-recursive
        MapPos mapPosM;
        if (SplitSegment(mapPos0, mapPos1, mapPosM)) {
            unsigned int iM = static_cast<int>(mapPoses.size());
            mapPoses.push_back(mapPosM);
            tesselateTriangle(i2, i0, iM, indices, mapPoses);
            tesselateTriangle(i1, i2, iM, indices, mapPoses);
            return;
        } else if (SplitSegment(mapPos0, mapPos2, mapPosM)) {
            unsigned int iM = static_cast<int>(mapPoses.size());
            mapPoses.push_back(mapPosM);
            tesselateTriangle(i0, i1, iM, indices, mapPoses);
            tesselateTriangle(i1, i2, iM, indices, mapPoses);
            return;
        } else if (SplitSegment(mapPos1, mapPos2, mapPosM)) {
            unsigned int iM = static_cast<int>(mapPoses.size());
            mapPoses.push_back(mapPosM);
            tesselateTriangle(i0, i1, iM, indices, mapPoses);
            tesselateTriangle(i2, i0, iM, indices, mapPoses);
            return;
        }

        indices.push_back(i0);
        indices.push_back(i1);
        indices.push_back(i2);
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateNearestPoint(const cglib::vec3<double>& pos, double height) const {
        return cglib::unit(pos) * (SPHERE_SIZE + height);
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateNearestPoint(const cglib::ray3<double>& ray, double height, double& t) const {
        if (calculateHitPoint(ray, height, t)) {
            return ray(t);
        }
        t = -cglib::dot_product(ray.origin, ray.direction) / cglib::norm(ray.direction);
        return cglib::unit(ray(t)) * (SPHERE_SIZE + height);
    }

    bool SphericalProjectionSurface::calculateHitPoint(const cglib::ray3<double>& ray, double height, double& t) const {
        double a = cglib::norm(ray.direction);
        double b = 2.0 * cglib::dot_product(ray.direction, ray.origin);
        double c = cglib::norm(ray.origin) - (SPHERE_SIZE + height) * (SPHERE_SIZE + height);
        double d = b * b - 4.0 * a * c;
        if (d < 0.0) {
            return false;
        }
        t = (-b - std::sqrt(d)) / (2.0 * a);
        return true;
    }

    cglib::mat4x4<double> SphericalProjectionSurface::calculateLocalFrameMatrix(const cglib::vec3<double>& pos) const {
        cglib::mat3x3<double> localFrameMat3 = LocalFrame(pos);
        cglib::mat4x4<double> localFrameMat4 = cglib::mat4x4<double>::identity();
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                localFrameMat4(i, j) = localFrameMat3(i, j) * SPHERE_SIZE;
            }
            localFrameMat4(i, 3) = pos(i);
        }
        return localFrameMat4;
    }

    cglib::mat4x4<double> SphericalProjectionSurface::calculateTranslateMatrix(const cglib::vec3<double>& pos0, const cglib::vec3<double>& pos1, double t) const {
        double dot = cglib::dot_product(cglib::unit(pos0), cglib::unit(pos1));
        double angle = std::acos(std::min(1.0, std::max(-1.0, dot)));
        cglib::vec3<double> axis = cglib::vector_product(cglib::unit(pos0), cglib::unit(pos1));
        if (cglib::length(axis) > 0) {
            if (angle < PLANAR_APPROX_ANGLE) { // less than 10m
                return cglib::translate4_matrix((cglib::unit(pos1) - cglib::unit(pos0)) * (SPHERE_SIZE * t));
            }
            return cglib::rotate4_matrix(axis, angle * t);
        }
        return cglib::mat4x4<double>::identity();
    }

    bool SphericalProjectionSurface::SplitSegment(const MapPos& mapPos0, const MapPos& mapPos1, MapPos& mapPosM) {
        cglib::vec3<double> pos0 = cglib::unit(InternalToSpherical(mapPos0));
        cglib::vec3<double> pos1 = cglib::unit(InternalToSpherical(mapPos1));
        double dot = cglib::dot_product(pos0, pos1);
        if (dot <= -1) {
            return false; // exactly on the opposite side, no way to split
        }
        double angle = std::acos(std::min(1.0, std::max(-1.0, dot)));
        if (angle * Const::EARTH_RADIUS < SEGMENT_SPLIT_THRESHOLD) {
            return false;
        }
        mapPosM = SphericalToInternal(cglib::unit(pos0 + pos1));
        return true;
    }

    MapPos SphericalProjectionSurface::SphericalToInternal(const cglib::vec3<double>& pos) {
        double scale = Const::WORLD_SIZE / (2 * Const::PI);
        double length = cglib::length(pos);
        double x1 = pos(0) != 0 || pos(1) != 0 ? std::atan2(pos(1), pos(0)) : 0;
        double y1 = std::atanh(std::max(-1.0, std::min(1.0, pos(2) / length)));
        double z1 = length - 1.0;
        return MapPos(x1 * scale, y1 * scale, z1 * Const::EARTH_RADIUS);
    }

    cglib::vec3<double> SphericalProjectionSurface::InternalToSpherical(const MapPos& mapPos) {
        double scale = 2 * Const::PI / Const::WORLD_SIZE;
        double x1 = mapPos.getX() * scale;
        double y1 = mapPos.getY() * scale;
        double rz = std::tanh(y1);
        double ss = std::sqrt(std::max(0.0, 1.0 - rz * rz));
        double rx = ss * std::cos(x1);
        double ry = ss * std::sin(x1);
        return cglib::vec3<double>(rx, ry, rz) * (1.0 + mapPos.getZ() / Const::EARTH_RADIUS);
    }

    cglib::mat3x3<double> SphericalProjectionSurface::LocalFrame(const cglib::vec3<double>& pos) {
        double x = pos(0);
        double y = pos(1);
        double z = pos(2);

        double dx_du = -y;
        double dy_du = x;
        double dz_du = 0;

        double dx_dv = -z * x;
        double dy_dv = -z * y;
        double dz_dv = x * x + y * y;

        double dx_dh = x;
        double dy_dh = y;
        double dz_dh = z;

        return cglib::mat3x3<double> { { dx_du, dx_dv, dx_dh }, { dy_du, dy_dv, dy_dh }, { dz_du, dz_dv, dz_dh } };
    }

    const double SphericalProjectionSurface::SPHERE_SIZE = Const::WORLD_SIZE / Const::PI;

    const double SphericalProjectionSurface::PLANAR_APPROX_ANGLE = 1.0e-6;

    const double SphericalProjectionSurface::SEGMENT_SPLIT_THRESHOLD = Const::EARTH_CIRCUMFERENCE / 180.0;

}
<commit_msg>Fixes to SphericalProjectionSurface<commit_after>#include "SphericalProjectionSurface.h"
#include "utils/Const.h"

namespace carto {

    SphericalProjectionSurface::SphericalProjectionSurface() {
    }

    MapPos SphericalProjectionSurface::calculateMapPos(const cglib::vec3<double>& pos) const {
        return SphericalToInternal(pos * (1.0 / SPHERE_SIZE));
    }

    MapVec SphericalProjectionSurface::calculateMapVec(const cglib::vec3<double>& pos, const cglib::vec3<double>& vec) const {
        cglib::vec3<double> xyzPos = pos * (1.0 / SPHERE_SIZE);
        cglib::mat3x3<double> xyzFrame = LocalFrame(xyzPos);
        double scale = std::sqrt(xyzPos(0) * xyzPos(0) + xyzPos(1) * xyzPos(1)) / Const::PI;
        cglib::vec3<double> mapVec = cglib::transform(vec, cglib::transpose(xyzFrame));
        return MapVec(mapVec(0) * scale, mapVec(1) * scale, mapVec(2) * scale);
    }

    double SphericalProjectionSurface::calculateMapDistance(const cglib::vec3<double> pos0, const cglib::vec3<double>& pos1) const {
        double dot = cglib::dot_product(cglib::unit(pos0), cglib::unit(pos1));
        double angle = std::acos(std::min(1.0, std::max(-1.0, dot)));
        if (angle < PLANAR_APPROX_ANGLE) {
            cglib::vec3<double> delta = cglib::unit(pos0) - cglib::unit(pos1);
            return cglib::length(delta) * Const::EARTH_RADIUS;
        }
        return angle * Const::EARTH_RADIUS;
    }

    cglib::vec3<double> SphericalProjectionSurface::calculatePosition(const MapPos& mapPos) const {
        return InternalToSpherical(mapPos) * SPHERE_SIZE;
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateNormal(const MapPos& mapPos) const {
        return InternalToSpherical(mapPos);
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateVector(const MapPos& mapPos, const MapVec& mapVec) const {
        cglib::vec3<double> xyzPos = InternalToSpherical(mapPos);
        cglib::mat3x3<double> xyzFrame = LocalFrame(xyzPos);
        double scale = Const::PI / std::sqrt(xyzPos(0) * xyzPos(0) + xyzPos(1) * xyzPos(1));
        return cglib::transform(cglib::vec3<double>(mapVec.getX() * scale, mapVec.getY() * scale, mapVec.getZ() * scale), xyzFrame);
    }

    void SphericalProjectionSurface::tesselateSegment(const MapPos& mapPos0, const MapPos& mapPos1, std::vector<MapPos>& mapPoses) const {
        // TODO: make it faster, non-recursive
        MapPos mapPosM;
        if (SplitSegment(mapPos0, mapPos1, mapPosM)) {
            tesselateSegment(mapPos0, mapPosM, mapPoses);
            tesselateSegment(mapPosM, mapPos1, mapPoses);
            return;
        }

        mapPoses.push_back(mapPos0);
        mapPoses.push_back(mapPos1);
    }

    void SphericalProjectionSurface::tesselateTriangle(unsigned int i0, unsigned int i1, unsigned int i2, std::vector<unsigned int>& indices, std::vector<MapPos>& mapPoses) const {
        const MapPos& mapPos0 = mapPoses.at(i0);
        const MapPos& mapPos1 = mapPoses.at(i1);
        const MapPos& mapPos2 = mapPoses.at(i2);

        // TODO: make it faster, non-recursive
        MapPos mapPosM;
        if (SplitSegment(mapPos0, mapPos1, mapPosM)) {
            unsigned int iM = static_cast<int>(mapPoses.size());
            mapPoses.push_back(mapPosM);
            tesselateTriangle(i2, i0, iM, indices, mapPoses);
            tesselateTriangle(i1, i2, iM, indices, mapPoses);
            return;
        } else if (SplitSegment(mapPos0, mapPos2, mapPosM)) {
            unsigned int iM = static_cast<int>(mapPoses.size());
            mapPoses.push_back(mapPosM);
            tesselateTriangle(i0, i1, iM, indices, mapPoses);
            tesselateTriangle(i1, i2, iM, indices, mapPoses);
            return;
        } else if (SplitSegment(mapPos1, mapPos2, mapPosM)) {
            unsigned int iM = static_cast<int>(mapPoses.size());
            mapPoses.push_back(mapPosM);
            tesselateTriangle(i0, i1, iM, indices, mapPoses);
            tesselateTriangle(i2, i0, iM, indices, mapPoses);
            return;
        }

        indices.push_back(i0);
        indices.push_back(i1);
        indices.push_back(i2);
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateNearestPoint(const cglib::vec3<double>& pos, double height) const {
        return cglib::unit(pos) * (SPHERE_SIZE + height);
    }

    cglib::vec3<double> SphericalProjectionSurface::calculateNearestPoint(const cglib::ray3<double>& ray, double height, double& t) const {
        if (calculateHitPoint(ray, height, t)) {
            return ray(t);
        }
        t = -cglib::dot_product(ray.origin, ray.direction) / cglib::norm(ray.direction);
        return cglib::unit(ray(t)) * (SPHERE_SIZE + height);
    }

    bool SphericalProjectionSurface::calculateHitPoint(const cglib::ray3<double>& ray, double height, double& t) const {
        double a = cglib::norm(ray.direction);
        double b = 2.0 * cglib::dot_product(ray.direction, ray.origin);
        double c = cglib::norm(ray.origin) - (SPHERE_SIZE + height) * (SPHERE_SIZE + height);
        double d = b * b - 4.0 * a * c;
        if (d < 0.0) {
            return false;
        }
        t = (-b - std::sqrt(d)) / (2.0 * a);
        return true;
    }

    cglib::mat4x4<double> SphericalProjectionSurface::calculateLocalFrameMatrix(const cglib::vec3<double>& pos) const {
        cglib::mat3x3<double> localFrameMat3 = LocalFrame(pos * (1.0 / SPHERE_SIZE));
        cglib::mat4x4<double> localFrameMat4 = cglib::mat4x4<double>::identity();
        for (int i = 0; i < 3; i++) {
            cglib::vec3<double> dir = cglib::unit(cglib::col_vector(localFrameMat3, i));
            for (int j = 0; j < 3; j++) {
                localFrameMat4(j, i) = dir(j) * SPHERE_SIZE / Const::EARTH_RADIUS;
            }
            localFrameMat4(i, 3) = pos(i);
        }
        return localFrameMat4;
    }

    cglib::mat4x4<double> SphericalProjectionSurface::calculateTranslateMatrix(const cglib::vec3<double>& pos0, const cglib::vec3<double>& pos1, double t) const {
        double dot = cglib::dot_product(cglib::unit(pos0), cglib::unit(pos1));
        double angle = std::acos(std::min(1.0, std::max(-1.0, dot)));
        cglib::vec3<double> axis = cglib::vector_product(cglib::unit(pos0), cglib::unit(pos1));
        if (cglib::length(axis) > 0) {
            if (angle < PLANAR_APPROX_ANGLE) { // less than 10m
                return cglib::translate4_matrix((cglib::unit(pos1) - cglib::unit(pos0)) * (SPHERE_SIZE * t));
            }
            return cglib::rotate4_matrix(axis, angle * t);
        }
        return cglib::mat4x4<double>::identity();
    }

    bool SphericalProjectionSurface::SplitSegment(const MapPos& mapPos0, const MapPos& mapPos1, MapPos& mapPosM) {
        cglib::vec3<double> pos0 = cglib::unit(InternalToSpherical(mapPos0));
        cglib::vec3<double> pos1 = cglib::unit(InternalToSpherical(mapPos1));
        double dot = cglib::dot_product(pos0, pos1);
        if (dot <= -1) {
            return false; // exactly on the opposite side, no way to split
        }
        double angle = std::acos(std::min(1.0, std::max(-1.0, dot)));
        if (angle * Const::EARTH_RADIUS < SEGMENT_SPLIT_THRESHOLD) {
            return false;
        }
        mapPosM = SphericalToInternal(cglib::unit(pos0 + pos1));
        return true;
    }

    MapPos SphericalProjectionSurface::SphericalToInternal(const cglib::vec3<double>& pos) {
        double scale = Const::WORLD_SIZE / (2 * Const::PI);
        double length = cglib::length(pos);
        double x1 = pos(0) != 0 || pos(1) != 0 ? std::atan2(pos(1), pos(0)) : 0;
        double y1 = std::atanh(std::max(-1.0, std::min(1.0, pos(2) / length)));
        double z1 = length - 1.0;
        return MapPos(x1 * scale, y1 * scale, z1 * scale);
    }

    cglib::vec3<double> SphericalProjectionSurface::InternalToSpherical(const MapPos& mapPos) {
        double scale = 2 * Const::PI / Const::WORLD_SIZE;
        double x1 = mapPos.getX() * scale;
        double y1 = mapPos.getY() * scale;
        double z1 = mapPos.getZ() * scale;
        double rz = std::tanh(y1);
        double ss = std::sqrt(std::max(0.0, 1.0 - rz * rz));
        double rx = ss * std::cos(x1);
        double ry = ss * std::sin(x1);
        return cglib::vec3<double>(rx, ry, rz) * (1.0 + z1);
    }

    cglib::mat3x3<double> SphericalProjectionSurface::LocalFrame(const cglib::vec3<double>& pos) {
        double x = pos(0);
        double y = pos(1);
        double z = pos(2);

        double dx_du = -y;
        double dy_du = x;
        double dz_du = 0;

        double dx_dv = -z * x;
        double dy_dv = -z * y;
        double dz_dv = x * x + y * y;

        double dx_dh = x;
        double dy_dh = y;
        double dz_dh = z;

        return cglib::mat3x3<double> { { dx_du, dx_dv, dx_dh }, { dy_du, dy_dv, dy_dh }, { dz_du, dz_dv, dz_dh } };
    }

    const double SphericalProjectionSurface::SPHERE_SIZE = Const::WORLD_SIZE / Const::PI;

    const double SphericalProjectionSurface::PLANAR_APPROX_ANGLE = 1.0e-6;

    const double SphericalProjectionSurface::SEGMENT_SPLIT_THRESHOLD = Const::EARTH_CIRCUMFERENCE / 120.0;

}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitCore                                                       *
 * @(#)root/roofitcore:$Id$
 * Authors:                                                                  *
 *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
 *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
 *                                                                           *
 * Copyright (c) 2000-2005, Regents of the University of California          *
 *                          and Stanford University. All rights reserved.    *
 *                                                                           *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/

//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// RooTruthModel is an implementation of RooResolution
// model that provides a delta-function resolution model
//

// The truth model supports all basis functions because it evaluates each basis function as
// as a RooFormulaVar.  The 6 basis functions used in B mixing and decay and 2 basis
// functions used in D mixing have been hand coded for increased execution speed.
// END_HTML
//

#include "RooFit.h"

#include "Riostream.h"
#include "Riostream.h"
#include "RooTruthModel.h"

ClassImp(RooTruthModel)
;

//_____________________________________________________________________________
RooTruthModel::RooTruthModel(const char *name, const char *title, RooRealVar& xIn) :
  RooResolutionModel(name,title,xIn)
{
  // Constructor of a truth resolution model, i.e. a delta function in observable 'xIn'

}

//_____________________________________________________________________________
RooTruthModel::RooTruthModel(const RooTruthModel& other, const char* name) :
  RooResolutionModel(other,name)
{
  // Copy constructor
}

//_____________________________________________________________________________
RooTruthModel::~RooTruthModel()
{
  // Destructor
}

//_____________________________________________________________________________
Int_t RooTruthModel::basisCode(const char* name) const
{
  // Return basis code for given basis definition string. Return special
  // codes for 'known' bases for which compiled definition exists. Return
  // generic bases code if implementation relies on TFormula interpretation
  // of basis name

  // Check for optimized basis functions
  if (!TString("exp(-@0/@1)").CompareTo(name)) return expBasisPlus ;
  if (!TString("exp(@0/@1)").CompareTo(name)) return expBasisMinus ;
  if (!TString("exp(-abs(@0)/@1)").CompareTo(name)) return expBasisSum ;
  if (!TString("exp(-@0/@1)*sin(@0*@2)").CompareTo(name)) return sinBasisPlus ;
  if (!TString("exp(@0/@1)*sin(@0*@2)").CompareTo(name)) return sinBasisMinus ;
  if (!TString("exp(-abs(@0)/@1)*sin(@0*@2)").CompareTo(name)) return sinBasisSum ;
  if (!TString("exp(-@0/@1)*cos(@0*@2)").CompareTo(name)) return cosBasisPlus ;
  if (!TString("exp(@0/@1)*cos(@0*@2)").CompareTo(name)) return cosBasisMinus ;
  if (!TString("exp(-abs(@0)/@1)*cos(@0*@2)").CompareTo(name)) return cosBasisSum ;
  if (!TString("(@0/@1)*exp(-@0/@1)").CompareTo(name)) return linBasisPlus ;
  if (!TString("(@0/@1)*(@0/@1)*exp(-@0/@1)").CompareTo(name)) return quadBasisPlus ;
  if (!TString("exp(-@0/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasisPlus;
  if (!TString("exp(@0/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasisMinus;
  if (!TString("exp(-abs(@0)/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasisSum;
  if (!TString("exp(-@0/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasisPlus;
  if (!TString("exp(@0/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasisMinus;
  if (!TString("exp(-abs(@0)/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasisSum;

  // Truth model is delta function, i.e. convolution integral
  // is basis function, therefore we can handle any basis function
  return genericBasis ;
}

//_____________________________________________________________________________
void RooTruthModel::changeBasis(RooFormulaVar* inBasis)
{
  // Changes associated bases function to 'inBasis'

  // Process change basis function. Since we actually
  // evaluate the basis function object, we need to
  // adjust our client-server links to the basis function here

  // Remove client-server link to old basis
  if (_basis) {
    removeServer(*_basis) ;
  }

  // Change basis pointer and update client-server link
  _basis = inBasis ;
  if (_basis) {
    addServer(*_basis,kTRUE,kFALSE) ;
  }

  _basisCode = inBasis?basisCode(inBasis->GetTitle()):0 ;
}

//_____________________________________________________________________________
Double_t RooTruthModel::evaluate() const
{
  // Evaluate the truth model: a delta function when used as PDF,
  // the basis function itself, when convoluted with a basis function.

  // No basis: delta function
  if (_basisCode == noBasis) {
    if (x==0) return 1 ;
    return 0 ;
  }

  // Generic basis: evaluate basis function object
  if (_basisCode == genericBasis) {
    return basis().getVal() ;
  }

  // Precompiled basis functions
  BasisType basisType = (BasisType)( (_basisCode == 0) ? 0 : (_basisCode/10) + 1 );
  BasisSign basisSign = (BasisSign)( _basisCode - 10*(basisType-1) - 2 ) ;

  // Enforce sign compatibility
  if ((basisSign==Minus && x>0) ||
      (basisSign==Plus  && x<0)) return 0 ;

  Double_t tau = ((RooAbsReal*)basis().getParameter(1))->getVal() ;
  // Return desired basis function
  switch(basisType) {
  case expBasis: {
    //cout << " RooTruthModel::eval(" << GetName() << ") expBasis mode ret = " << exp(-fabs((Double_t)x)/tau) << " tau = " << tau << endl ;
    return exp(-fabs((Double_t)x)/tau) ;
  }
  case sinBasis: {
    Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*sin(x*dm) ;
  }
  case cosBasis: {
    Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*cos(x*dm) ;
  }
  case linBasis: {
    Double_t tscaled = fabs((Double_t)x)/tau;
    return exp(-tscaled)*tscaled ;
  }
  case quadBasis: {
    Double_t tscaled = fabs((Double_t)x)/tau;
    return exp(-tscaled)*tscaled*tscaled;
  }
  case sinhBasis: {
    Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*sinh(x*dg/2) ;
  }
  case coshBasis: {
    Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*cosh(x*dg/2) ;
  }
  default:
    assert(0) ;
  }

  return 0 ;
}

//_____________________________________________________________________________
Int_t RooTruthModel::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
{
  // Advertise analytical integrals for compiled basis functions and when used
  // as p.d.f without basis function.

  switch(_basisCode) {

  // Analytical integration capability of raw PDF
  case noBasis:
    if (matchArgs(allVars,analVars,convVar())) return 1 ;
    break ;

  // Analytical integration capability of convoluted PDF
  case expBasisPlus:
  case expBasisMinus:
  case expBasisSum:
  case sinBasisPlus:
  case sinBasisMinus:
  case sinBasisSum:
  case cosBasisPlus:
  case cosBasisMinus:
  case cosBasisSum:
  case linBasisPlus:
  case quadBasisPlus:
  case sinhBasisPlus:
  case sinhBasisMinus:
  case sinhBasisSum:
  case coshBasisPlus:
  case coshBasisMinus:
  case coshBasisSum:
    if (matchArgs(allVars,analVars,convVar())) return 1 ;
    break ;
  }

  return 0 ;
}

//_____________________________________________________________________________
Double_t RooTruthModel::analyticalIntegral(Int_t code, const char* rangeName) const
{
  // Implement analytical integrals when used as p.d.f and for compiled
  // basis functions.

  // Code must be 1
  assert(code==1) ;

  // Unconvoluted PDF
  if (_basisCode==noBasis) return 1 ;

  // Precompiled basis functions
  BasisType basisType = (BasisType)( (_basisCode == 0) ? 0 : (_basisCode/10) + 1 );
  BasisSign basisSign = (BasisSign)( _basisCode - 10*(basisType-1) - 2 ) ;
  //cout << " calling RooTruthModel::analyticalIntegral with basisType " << basisType << endl;

  Double_t tau = ((RooAbsReal*)basis().getParameter(1))->getVal() ;
  switch (basisType) {
  case expBasis:
    {
      // WVE fixed for ranges
      Double_t result(0) ;
      if (tau==0) return 1 ;
      if (basisSign != Minus) result += tau*(exp(-x.min(rangeName)/tau)-exp(-x.max(rangeName)/tau)) ;
      if (basisSign != Plus) result += tau*(exp(-x.max(rangeName)/tau)-exp(x.min(rangeName)/tau)) ;
      //cout << "RooTruthModel::ai(" << GetName() << ") rangeName = " << rangeName << " ret = " << result << endl ;
      return result ;
    }
  case sinBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 0 ;
      Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      if (basisSign != Minus) result += exp(-x.max(rangeName)/tau)*(-1/tau*sin(dm*x.max(rangeName)) - dm*cos(dm*x.max(rangeName))) + dm;  // fixed FMV 08/29/03
      if (basisSign != Plus)  result -= exp( x.min(rangeName)/tau)*(-1/tau*sin(dm*(-x.min(rangeName))) - dm*cos(dm*(-x.min(rangeName)))) + dm ;  // fixed FMV 08/29/03
      return result / (1/(tau*tau) + dm*dm) ;
    }
  case cosBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 1 ;
      Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      if (basisSign != Minus) result += exp(-x.max(rangeName)/tau)*(-1/tau*cos(dm*x.max(rangeName)) + dm*sin(dm*x.max(rangeName))) + 1/tau ;
      if (basisSign != Plus)  result += exp( x.min(rangeName)/tau)*(-1/tau*cos(dm*(-x.min(rangeName))) + dm*sin(dm*(-x.min(rangeName)))) + 1/tau ; // fixed FMV 08/29/03
      return result / (1/(tau*tau) + dm*dm) ;
    }
  case linBasis:
    {
      if (tau==0) return 0 ;
      Double_t t_max = x.max(rangeName)/tau ;
      return tau*( 1 - (1 + t_max)*exp(-t_max) ) ;
    }
  case quadBasis:
    {
      if (tau==0) return 0 ;
      Double_t t_max = x.max(rangeName)/tau ;
      return tau*( 2 - (2 + (2 + t_max)*t_max)*exp(-t_max) ) ;
    }
  case sinhBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 0 ;
      Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      Double_t taup = 2*tau/(2-tau*dg);
      Double_t taum = 2*tau/(2+tau*dg);
      if (basisSign != Minus) result += 0.5*( taup*(1-exp(-x.max(rangeName)/taup)) - taum*(1-exp(-x.max(rangeName)/taum)) ) ;
      if (basisSign != Plus)  result -= 0.5*( taup*(1-exp( x.min(rangeName)/taup)) - taum*(1-exp( x.min(rangeName)/taum)) ) ;
      return result ;
    }
  case coshBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 1 ;
      Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      Double_t taup = 2*tau/(2-tau*dg);
      Double_t taum = 2*tau/(2+tau*dg);
      if (basisSign != Minus) result += 0.5*( taup*(1-exp(-x.max(rangeName)/taup)) + taum*(1-exp(-x.max(rangeName)/taum)) ) ;
      if (basisSign != Plus)  result += 0.5*( taup*(1-exp( x.min(rangeName)/taup)) + taum*(1-exp( x.min(rangeName)/taum)) ) ;
      return result ;
    }
  default:
    assert(0) ;
  }

  assert(0) ;
  return 0 ;
}

//_____________________________________________________________________________
Int_t RooTruthModel::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t /*staticInitOK*/) const
{
  // Advertise internal generator for observable x
  if (matchArgs(directVars,generateVars,x)) return 1 ;
  return 0 ;
}

//_____________________________________________________________________________
void RooTruthModel::generateEvent(Int_t code)
{
  // Implement internal generator for observable x,
  // x=0 for all events following definition
  // of delta function

  assert(code==1) ;
  Double_t zero(0.) ;
  x = zero ;
  return;
}
<commit_msg><commit_after>/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitCore                                                       *
 * @(#)root/roofitcore:$Id$
 * Authors:                                                                  *
 *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
 *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
 *                                                                           *
 * Copyright (c) 2000-2005, Regents of the University of California          *
 *                          and Stanford University. All rights reserved.    *
 *                                                                           *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/

//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// RooTruthModel is an implementation of RooResolution
// model that provides a delta-function resolution model
//

// The truth model supports all basis functions because it evaluates each basis function as
// as a RooFormulaVar.  The 6 basis functions used in B mixing and decay and 2 basis
// functions used in D mixing have been hand coded for increased execution speed.
// END_HTML
//

#include "RooFit.h"

#include "Riostream.h"
#include "Riostream.h"
#include "RooTruthModel.h"
#include <algorithm>
using namespace std ;

ClassImp(RooTruthModel)
;

//_____________________________________________________________________________
RooTruthModel::RooTruthModel(const char *name, const char *title, RooRealVar& xIn) :
  RooResolutionModel(name,title,xIn)
{
  // Constructor of a truth resolution model, i.e. a delta function in observable 'xIn'

}

//_____________________________________________________________________________
RooTruthModel::RooTruthModel(const RooTruthModel& other, const char* name) :
  RooResolutionModel(other,name)
{
  // Copy constructor
}

//_____________________________________________________________________________
RooTruthModel::~RooTruthModel()
{
  // Destructor
}

//_____________________________________________________________________________
Int_t RooTruthModel::basisCode(const char* name) const
{
  // Return basis code for given basis definition string. Return special
  // codes for 'known' bases for which compiled definition exists. Return
  // generic bases code if implementation relies on TFormula interpretation
  // of basis name

  // Check for optimized basis functions
  if (!TString("exp(-@0/@1)").CompareTo(name)) return expBasisPlus ;
  if (!TString("exp(@0/@1)").CompareTo(name)) return expBasisMinus ;
  if (!TString("exp(-abs(@0)/@1)").CompareTo(name)) return expBasisSum ;
  if (!TString("exp(-@0/@1)*sin(@0*@2)").CompareTo(name)) return sinBasisPlus ;
  if (!TString("exp(@0/@1)*sin(@0*@2)").CompareTo(name)) return sinBasisMinus ;
  if (!TString("exp(-abs(@0)/@1)*sin(@0*@2)").CompareTo(name)) return sinBasisSum ;
  if (!TString("exp(-@0/@1)*cos(@0*@2)").CompareTo(name)) return cosBasisPlus ;
  if (!TString("exp(@0/@1)*cos(@0*@2)").CompareTo(name)) return cosBasisMinus ;
  if (!TString("exp(-abs(@0)/@1)*cos(@0*@2)").CompareTo(name)) return cosBasisSum ;
  if (!TString("(@0/@1)*exp(-@0/@1)").CompareTo(name)) return linBasisPlus ;
  if (!TString("(@0/@1)*(@0/@1)*exp(-@0/@1)").CompareTo(name)) return quadBasisPlus ;
  if (!TString("exp(-@0/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasisPlus;
  if (!TString("exp(@0/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasisMinus;
  if (!TString("exp(-abs(@0)/@1)*cosh(@0*@2/2)").CompareTo(name)) return coshBasisSum;
  if (!TString("exp(-@0/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasisPlus;
  if (!TString("exp(@0/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasisMinus;
  if (!TString("exp(-abs(@0)/@1)*sinh(@0*@2/2)").CompareTo(name)) return sinhBasisSum;

  // Truth model is delta function, i.e. convolution integral
  // is basis function, therefore we can handle any basis function
  return genericBasis ;
}

//_____________________________________________________________________________
void RooTruthModel::changeBasis(RooFormulaVar* inBasis)
{
  // Changes associated bases function to 'inBasis'

  // Process change basis function. Since we actually
  // evaluate the basis function object, we need to
  // adjust our client-server links to the basis function here

  // Remove client-server link to old basis
  if (_basis) {
    removeServer(*_basis) ;
  }

  // Change basis pointer and update client-server link
  _basis = inBasis ;
  if (_basis) {
    addServer(*_basis,kTRUE,kFALSE) ;
  }

  _basisCode = inBasis?basisCode(inBasis->GetTitle()):0 ;
}

//_____________________________________________________________________________
Double_t RooTruthModel::evaluate() const
{
  // Evaluate the truth model: a delta function when used as PDF,
  // the basis function itself, when convoluted with a basis function.

  // No basis: delta function
  if (_basisCode == noBasis) {
    if (x==0) return 1 ;
    return 0 ;
  }

  // Generic basis: evaluate basis function object
  if (_basisCode == genericBasis) {
    return basis().getVal() ;
  }

  // Precompiled basis functions
  BasisType basisType = (BasisType)( (_basisCode == 0) ? 0 : (_basisCode/10) + 1 );
  BasisSign basisSign = (BasisSign)( _basisCode - 10*(basisType-1) - 2 ) ;

  // Enforce sign compatibility
  if ((basisSign==Minus && x>0) ||
      (basisSign==Plus  && x<0)) return 0 ;

  Double_t tau = ((RooAbsReal*)basis().getParameter(1))->getVal() ;
  // Return desired basis function
  switch(basisType) {
  case expBasis: {
    //cout << " RooTruthModel::eval(" << GetName() << ") expBasis mode ret = " << exp(-fabs((Double_t)x)/tau) << " tau = " << tau << endl ;
    return exp(-fabs((Double_t)x)/tau) ;
  }
  case sinBasis: {
    Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*sin(x*dm) ;
  }
  case cosBasis: {
    Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*cos(x*dm) ;
  }
  case linBasis: {
    Double_t tscaled = fabs((Double_t)x)/tau;
    return exp(-tscaled)*tscaled ;
  }
  case quadBasis: {
    Double_t tscaled = fabs((Double_t)x)/tau;
    return exp(-tscaled)*tscaled*tscaled;
  }
  case sinhBasis: {
    Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*sinh(x*dg/2) ;
  }
  case coshBasis: {
    Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
    return exp(-fabs((Double_t)x)/tau)*cosh(x*dg/2) ;
  }
  default:
    assert(0) ;
  }

  return 0 ;
}

//_____________________________________________________________________________
Int_t RooTruthModel::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /*rangeName*/) const
{
  // Advertise analytical integrals for compiled basis functions and when used
  // as p.d.f without basis function.

  switch(_basisCode) {

  // Analytical integration capability of raw PDF
  case noBasis:
    if (matchArgs(allVars,analVars,convVar())) return 1 ;
    break ;

  // Analytical integration capability of convoluted PDF
  case expBasisPlus:
  case expBasisMinus:
  case expBasisSum:
  case sinBasisPlus:
  case sinBasisMinus:
  case sinBasisSum:
  case cosBasisPlus:
  case cosBasisMinus:
  case cosBasisSum:
  case linBasisPlus:
  case quadBasisPlus:
  case sinhBasisPlus:
  case sinhBasisMinus:
  case sinhBasisSum:
  case coshBasisPlus:
  case coshBasisMinus:
  case coshBasisSum:
    if (matchArgs(allVars,analVars,convVar())) return 1 ;
    break ;
  }

  return 0 ;
}

//_____________________________________________________________________________
Double_t RooTruthModel::analyticalIntegral(Int_t code, const char* rangeName) const
{
  // Implement analytical integrals when used as p.d.f and for compiled
  // basis functions.

  // Code must be 1
  assert(code==1) ;

  // Unconvoluted PDF
  if (_basisCode==noBasis) return 1 ;

  // Precompiled basis functions
  BasisType basisType = (BasisType)( (_basisCode == 0) ? 0 : (_basisCode/10) + 1 );
  BasisSign basisSign = (BasisSign)( _basisCode - 10*(basisType-1) - 2 ) ;
  //cout << " calling RooTruthModel::analyticalIntegral with basisType " << basisType << endl;

  Double_t tau = ((RooAbsReal*)basis().getParameter(1))->getVal() ;
  switch (basisType) {
  case expBasis:
    {
      // WVE fixed for ranges
      Double_t result(0) ;
      if (tau==0) return 1 ;
      if ((basisSign != Minus) && (x.max(rangeName)>0)) {
	result += tau*(-exp(-x.max(rangeName)/tau) -  -exp(-max(0.,x.min(rangeName))/tau) ) ; // plus and both
      }
      if ((basisSign != Plus) && (x.min(rangeName)<0)) {
	result -= tau*(-exp(-max(0.,x.min(rangeName))/tau)) - -tau*exp(-x.max(rangeName)/tau) ;   // minus and both
      }

      return result ;
    }
  case sinBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 0 ;
      Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      if (basisSign != Minus) result += exp(-x.max(rangeName)/tau)*(-1/tau*sin(dm*x.max(rangeName)) - dm*cos(dm*x.max(rangeName))) + dm;  // fixed FMV 08/29/03
      if (basisSign != Plus)  result -= exp( x.min(rangeName)/tau)*(-1/tau*sin(dm*(-x.min(rangeName))) - dm*cos(dm*(-x.min(rangeName)))) + dm ;  // fixed FMV 08/29/03
      return result / (1/(tau*tau) + dm*dm) ;
    }
  case cosBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 1 ;
      Double_t dm = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      if (basisSign != Minus) result += exp(-x.max(rangeName)/tau)*(-1/tau*cos(dm*x.max(rangeName)) + dm*sin(dm*x.max(rangeName))) + 1/tau ;
      if (basisSign != Plus)  result += exp( x.min(rangeName)/tau)*(-1/tau*cos(dm*(-x.min(rangeName))) + dm*sin(dm*(-x.min(rangeName)))) + 1/tau ; // fixed FMV 08/29/03
      return result / (1/(tau*tau) + dm*dm) ;
    }
  case linBasis:
    {
      if (tau==0) return 0 ;
      Double_t t_max = x.max(rangeName)/tau ;
      return tau*( 1 - (1 + t_max)*exp(-t_max) ) ;
    }
  case quadBasis:
    {
      if (tau==0) return 0 ;
      Double_t t_max = x.max(rangeName)/tau ;
      return tau*( 2 - (2 + (2 + t_max)*t_max)*exp(-t_max) ) ;
    }
  case sinhBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 0 ;
      Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      Double_t taup = 2*tau/(2-tau*dg);
      Double_t taum = 2*tau/(2+tau*dg);
      if (basisSign != Minus) result += 0.5*( taup*(1-exp(-x.max(rangeName)/taup)) - taum*(1-exp(-x.max(rangeName)/taum)) ) ;
      if (basisSign != Plus)  result -= 0.5*( taup*(1-exp( x.min(rangeName)/taup)) - taum*(1-exp( x.min(rangeName)/taum)) ) ;
      return result ;
    }
  case coshBasis:
    {
      Double_t result(0) ;
      if (tau==0) return 1 ;
      Double_t dg = ((RooAbsReal*)basis().getParameter(2))->getVal() ;
      Double_t taup = 2*tau/(2-tau*dg);
      Double_t taum = 2*tau/(2+tau*dg);
      if (basisSign != Minus) result += 0.5*( taup*(1-exp(-x.max(rangeName)/taup)) + taum*(1-exp(-x.max(rangeName)/taum)) ) ;
      if (basisSign != Plus)  result += 0.5*( taup*(1-exp( x.min(rangeName)/taup)) + taum*(1-exp( x.min(rangeName)/taum)) ) ;
      return result ;
    }
  default:
    assert(0) ;
  }

  assert(0) ;
  return 0 ;
}

//_____________________________________________________________________________
Int_t RooTruthModel::getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, Bool_t /*staticInitOK*/) const
{
  // Advertise internal generator for observable x
  if (matchArgs(directVars,generateVars,x)) return 1 ;
  return 0 ;
}

//_____________________________________________________________________________
void RooTruthModel::generateEvent(Int_t code)
{
  // Implement internal generator for observable x,
  // x=0 for all events following definition
  // of delta function

  assert(code==1) ;
  Double_t zero(0.) ;
  x = zero ;
  return;
}
<|endoftext|>


<commit_before>/************************************************
 * libgo sample5
*************************************************/

/***********************************************
 * 结合boost.asio, 使网络编程变得更加简单.
 * 如果你不喜欢boost.asio, 这个例子可以跳过不看.
************************************************/
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include "coroutine.h"
#include "win_exit.h"

static const uint16_t port = 43332;
using namespace boost::asio;
using namespace boost::asio::ip;
using boost::system::error_code;

io_service ios;

tcp::endpoint addr(address::from_string("127.0.0.1"), port);

void echo_server()
{
    tcp::acceptor acc(ios, addr, true);
    for (int i = 0; i < 2; ++i) {
        std::shared_ptr<tcp::socket> s(new tcp::socket(ios));
        error_code ec;
        acc.accept(*s, ec);
        if (ec) {
            printf("line:%d accept error:%s\n", __LINE__, ec.message().c_str());
            return;
        }

        go [s]{
            char buf[1024];
            error_code ec;
            auto n = s->read_some(buffer(buf), ec);
            if (ec) {
                printf("line:%d read_some error:%s\n", __LINE__, ec.message().c_str());
                return;
            }

            n = s->write_some(buffer(buf, n), ec);
            if (ec) {
                printf("line:%d write_some error:%s\n", __LINE__, ec.message().c_str());
                return;
            }

            error_code ignore_ec;
            n = s->read_some(buffer(buf, 1), ignore_ec);
        };
    }
}

void client()
{
    tcp::socket s(ios);
    printf("start connect\n");
    error_code ec;
    s.connect(addr, ec);
    if (ec) {
        printf("line:%d connect error:%s\n", __LINE__, ec.message().c_str());
        return;
    }

    printf("connected success\n");

    std::string msg = "1234";
    int n = s.write_some(buffer(msg), ec);
    if (ec) {
        printf("line:%d write_some error:%s\n", __LINE__, ec.message().c_str());
        return;
    }

    printf("client send msg [%d] %s\n", (int)msg.size(), msg.c_str());
    char buf[12];
    n = s.receive(buffer(buf, n));
    printf("client recv msg [%d] %.*s\n", n, n, buf);
}

int main()
{
    go echo_server;
    go client;
    go client;

    // 200ms后安全退出
    std::thread([]{ co_sleep(200); co_sched.Stop(); }).detach();

    // 单线程执行
    co_sched.Start();
    return 0;
}

<commit_msg>sample5同时监听多个端口<commit_after>/************************************************
 * libgo sample5
*************************************************/

/***********************************************
 * 结合boost.asio, 使网络编程变得更加简单.
 * 如果你不喜欢boost.asio, 这个例子可以跳过不看.
************************************************/
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include "coroutine.h"
#include "win_exit.h"

static const uint16_t port = 43332;
using namespace boost::asio;
using namespace boost::asio::ip;
using boost::system::error_code;

io_service ios;

void echo_server(tcp::endpoint const& addr)
{
    tcp::acceptor acc(ios, addr, true);
    for (int i = 0; i < 2; ++i) {
        std::shared_ptr<tcp::socket> s(new tcp::socket(ios));
        error_code ec;
        acc.accept(*s, ec);
        if (ec) {
            printf("line:%d accept error:%s\n", __LINE__, ec.message().c_str());
            return;
        }

        go [s]{
            char buf[1024];
            error_code ec;
            auto n = s->read_some(buffer(buf), ec);
            if (ec) {
                printf("line:%d read_some error:%s\n", __LINE__, ec.message().c_str());
                return;
            }

            n = s->write_some(buffer(buf, n), ec);
            if (ec) {
                printf("line:%d write_some error:%s\n", __LINE__, ec.message().c_str());
                return;
            }

            error_code ignore_ec;
            n = s->read_some(buffer(buf, 1), ignore_ec);
        };
    }
}

void client(tcp::endpoint const& addr)
{
    tcp::socket s(ios);
    printf("start connect\n");
    error_code ec;
    s.connect(addr, ec);
    if (ec) {
        printf("line:%d connect error:%s\n", __LINE__, ec.message().c_str());
        return;
    }

    printf("connected success\n");

    std::string msg = "1234";
    int n = s.write_some(buffer(msg), ec);
    if (ec) {
        printf("line:%d write_some error:%s\n", __LINE__, ec.message().c_str());
        return;
    }

    printf("client send msg [%d] %s\n", (int)msg.size(), msg.c_str());
    char buf[12];
    n = s.receive(buffer(buf, n));
    printf("client recv msg [%d] %.*s\n", n, n, buf);
}

int main()
{
    for (int i = 0; i < 5; ++i) {
        tcp::endpoint addr(address::from_string("127.0.0.1"), port + i);
        go [addr]{ echo_server(addr); };
        go [addr]{ client(addr); };
    }

    // 200ms后安全退出
    std::thread([]{ co_sleep(200); co_sched.Stop(); }).detach();

    // 单线程执行
    co_sched.Start();
    return 0;
}

<|endoftext|>