<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// 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 author nor the names of other 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 OWNER 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 "stdafx.h"

#include <cursespp/App.h>
#include <cursespp/Colors.h>
#include <cursespp/DialogOverlay.h>
#include <cursespp/Screen.h>
#include <cursespp/SingleLineEntry.h>

#include <core/library/Indexer.h>
#include <core/library/LocalLibraryConstants.h>
#include <core/support/PreferenceKeys.h>

#include <app/query/SearchTrackListQuery.h>
#include <app/util/Hotkeys.h>
#include <app/util/PreferenceKeys.h>

#include "SettingsLayout.h"

using namespace musik;
using namespace musik::core::library::constants;
using namespace musik::core;
using namespace musik::box;
using namespace cursespp;
using namespace std::placeholders;

#define LABEL_HEIGHT 1
#define INPUT_HEIGHT 3
#define HOTKEY_INPUT_WIDTH 20

#define TOP(w) w->GetY()
#define BOTTOM(w) (w->GetY() + w->GetHeight())
#define LEFT(w) w->GetX()
#define RIGHT(w) (w->GetX() + w->GetWidth())

#define CREATE_CHECKBOX(checkbox, caption) \
    checkbox.reset(new cursespp::Checkbox()); \
    checkbox->SetText(caption); \
    checkbox->CheckChanged.connect(this, &SettingsLayout::OnCheckboxChanged);

using EntryPtr = IScrollAdapter::EntryPtr;

static bool showDotfiles = false;

SettingsLayout::SettingsLayout(musik::core::LibraryPtr library)
: LayoutBase()
, library(library)
, indexer(library->Indexer()) {
    this->prefs = Preferences::ForComponent(core::prefs::components::Settings);
    this->indexer->PathsUpdated.connect(this, &SettingsLayout::RefreshAddedPaths);
    this->InitializeWindows();
}

SettingsLayout::~SettingsLayout() {
}

void SettingsLayout::OnCheckboxChanged(cursespp::Checkbox* cb, bool checked) {
    if (cb == removeCheckbox.get()) {
        this->prefs->SetBool(core::prefs::keys::RemoveMissingFiles, checked);
        this->prefs->Save();
    }
    else if (cb == dotfileCheckbox.get()) {
        showDotfiles = !showDotfiles;
        this->browseAdapter.SetDotfilesVisible(showDotfiles);
        this->browseList->OnAdapterChanged();
    }
    else if (cb == focusShortcutsCheckbox.get()) {
        this->prefs->SetBool(box::prefs::keys::EscFocusesShortcuts, checked);
        this->prefs->Save();
    }
    else if (cb == customColorsCheckbox.get()) {
        this->prefs->SetBool(box::prefs::keys::DisableCustomColors, checked);
        this->prefs->Save();
    }
}

void SettingsLayout::Layout() {
    int x = this->GetX(), y = this->GetY();
    int cx = this->GetWidth(), cy = this->GetHeight();

    int startY = 0;
    int leftX = 0;
    int leftWidth = cx / 3; /* 1/3 width */
    int rightX = leftWidth;
    int rightWidth = cx - rightX; /* remainder (~2/3) */

    this->browseLabel->MoveAndResize(leftX + 1, startY, leftWidth - 1, LABEL_HEIGHT);
    this->addedPathsLabel->MoveAndResize(rightX + 1, startY, rightWidth - 1, LABEL_HEIGHT);

    int pathListsY = BOTTOM(this->browseLabel);
    int pathsHeight = (cy - pathListsY) / 2;

    this->browseList->MoveAndResize(leftX, pathListsY, leftWidth, pathsHeight);
    this->addedPathsList->MoveAndResize(rightX, pathListsY, rightWidth, pathsHeight);

    this->dotfileCheckbox->MoveAndResize(1, BOTTOM(this->browseList), cx - 1, LABEL_HEIGHT);
    this->removeCheckbox->MoveAndResize(1, BOTTOM(this->dotfileCheckbox), cx - 1, LABEL_HEIGHT);
    this->focusShortcutsCheckbox->MoveAndResize(1, BOTTOM(this->removeCheckbox), cx - 1, LABEL_HEIGHT);
    this->customColorsCheckbox->MoveAndResize(1, BOTTOM(this->focusShortcutsCheckbox), cx - 1, LABEL_HEIGHT);

    this->hotkeyLabel->MoveAndResize(
        1,
        BOTTOM(this->customColorsCheckbox) + 2,
        this->hotkeyLabel->Length(),
        LABEL_HEIGHT);

    this->hotkeyInput->MoveAndResize(
        RIGHT(this->hotkeyLabel),
        BOTTOM(this->customColorsCheckbox) + 1,
        HOTKEY_INPUT_WIDTH,
        INPUT_HEIGHT);
}

void SettingsLayout::RefreshAddedPaths() {
    this->addedPathsAdapter.Clear();

    std::vector<std::string> paths;
    this->indexer->GetPaths(paths);

    for (size_t i = 0; i < paths.size(); i++) {
        auto v = paths.at(i);
        auto e = EntryPtr(new SingleLineEntry(v));
        this->addedPathsAdapter.AddEntry(e);
    }

    this->addedPathsList->OnAdapterChanged();
}

int64 SettingsLayout::ListItemDecorator(
    ScrollableWindow* scrollable,
    size_t index,
    size_t line,
    IScrollAdapter::EntryPtr entry)
{
    if (scrollable == this->addedPathsList.get() ||
        scrollable == this->browseList.get())
    {
         ListWindow* lw = static_cast<ListWindow*>(scrollable);
         if (lw->GetSelectedIndex() == index) {
             return COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM);
         }
    }
    return -1;
}

void SettingsLayout::InitializeWindows() {
    this->SetFrameVisible(false);

    this->browseLabel.reset(new TextLabel());
    this->browseLabel->SetText("browse (SPACE to add)", text::AlignLeft);

    this->addedPathsLabel.reset(new TextLabel());
    this->addedPathsLabel->SetText("indexed paths (BACKSPACE to remove)", text::AlignLeft);

    this->addedPathsList.reset(new cursespp::ListWindow(&this->addedPathsAdapter));
    this->browseList.reset(new cursespp::ListWindow(&this->browseAdapter));

    ScrollAdapterBase::ItemDecorator decorator =
        std::bind(
            &SettingsLayout::ListItemDecorator,
            this,
            std::placeholders::_1,
            std::placeholders::_2,
            std::placeholders::_3,
            std::placeholders::_4);

    this->addedPathsAdapter.SetItemDecorator(decorator);
    this->browseAdapter.SetItemDecorator(decorator);

    CREATE_CHECKBOX(this->dotfileCheckbox, "show dotfiles in directory browser");
    CREATE_CHECKBOX(this->removeCheckbox, "remove missing files from library");
    CREATE_CHECKBOX(this->focusShortcutsCheckbox, "esc key focuses shortcuts bar");
    CREATE_CHECKBOX(this->customColorsCheckbox, "disable custom colors (requires restart)");

    this->hotkeyLabel.reset(new TextLabel());
    this->hotkeyLabel->SetText("hotkey tester: ");
    this->hotkeyInput.reset(new TextInput(IInput::InputRaw));

    this->browseList->SetFocusOrder(0);
    this->addedPathsList->SetFocusOrder(1);
    this->dotfileCheckbox->SetFocusOrder(2);
    this->removeCheckbox->SetFocusOrder(3);
    this->focusShortcutsCheckbox->SetFocusOrder(4);
    this->customColorsCheckbox->SetFocusOrder(5);
    this->hotkeyInput->SetFocusOrder(6);

    this->AddWindow(this->browseLabel);
    this->AddWindow(this->addedPathsLabel);
    this->AddWindow(this->browseList);
    this->AddWindow(this->addedPathsList);
    this->AddWindow(this->dotfileCheckbox);
    this->AddWindow(this->removeCheckbox);
    this->AddWindow(this->focusShortcutsCheckbox);
    this->AddWindow(this->customColorsCheckbox);
    this->AddWindow(this->hotkeyLabel);
    this->AddWindow(this->hotkeyInput);
}

void SettingsLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) {
    if (shortcuts) {
        shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateSettings), "settings");
        shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateLibrary), "library");
        shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateConsole), "console");
        shortcuts->AddShortcut("^D", "quit");
        shortcuts->SetActive(Hotkeys::Get(Hotkeys::NavigateSettings));
    }
}

void SettingsLayout::OnVisibilityChanged(bool visible) {
    LayoutBase::OnVisibilityChanged(visible);

    if (visible) {
        this->RefreshAddedPaths();
        this->LoadPreferences();
        this->CheckShowFirstRunDialog();
    }
}

void SettingsLayout::CheckShowFirstRunDialog() {
    if (!this->prefs->GetBool(box::prefs::keys::FirstRunSettingsDisplayed)) {
        std::shared_ptr<DialogOverlay> dialog(new DialogOverlay());

        dialog->SetTitle("welcome to musikbox!")
            .SetMessage("you need to add some directories that contain music files, "
                "then switch to the library view by pressing 'a' to start listening!\n\n"
                "for verbose system information, press '`' to enter the console view.\n\n"
                "select 'ok' to get started.");

        dialog->AddButton(
            "KEY_ENTER",
            "ENTER",
            "ok",
            [this](std::string key) {
                this->prefs->SetBool(box::prefs::keys::FirstRunSettingsDisplayed, true);
            });

        App::Overlays().Push(dialog);
    }
}

void SettingsLayout::LoadPreferences() {
    this->removeCheckbox->SetChecked(this->prefs->GetBool(core::prefs::keys::RemoveMissingFiles, true));
    this->focusShortcutsCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::EscFocusesShortcuts, true));
    this->customColorsCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::DisableCustomColors));
}

void SettingsLayout::AddSelectedDirectory() {
    size_t index = this->browseList->GetSelectedIndex();
    std::string path = this->browseAdapter.GetFullPathAt(index);

    if (path.size()) {
        this->indexer->AddPath(path);
    }
}

void SettingsLayout::RemoveSelectedDirectory() {
    std::vector<std::string> paths;
    this->indexer->GetPaths(paths);
    size_t index = this->addedPathsList->GetSelectedIndex();
    this->indexer->RemovePath(paths.at(index));
}

void SettingsLayout::DrillIntoSelectedDirectory() {
    this->browseAdapter.Select(this->browseList->GetSelectedIndex());
    this->browseList->SetSelectedIndex(0);
    this->browseList->OnAdapterChanged();
}

bool SettingsLayout::KeyPress(const std::string& key) {
    if (key == "KEY_ENTER") {
        if (this->GetFocus() == this->browseList) {
            this->DrillIntoSelectedDirectory();
            return true;
        }
    }
    else if (key == " ") {
        if (this->GetFocus() == this->browseList) {
            this->AddSelectedDirectory();
            return true;
        }
    }
    else if (key == "KEY_BACKSPACE") { /* backspace */
        if (this->GetFocus() == this->addedPathsList) {
            this->RemoveSelectedDirectory();
            return true;
        }
    }

    return LayoutBase::KeyPress(key);
}
<commit_msg>Cleaned up first run dialog text.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// 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 author nor the names of other 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 OWNER 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 "stdafx.h"

#include <cursespp/App.h>
#include <cursespp/Colors.h>
#include <cursespp/DialogOverlay.h>
#include <cursespp/Screen.h>
#include <cursespp/SingleLineEntry.h>

#include <core/library/Indexer.h>
#include <core/library/LocalLibraryConstants.h>
#include <core/support/PreferenceKeys.h>

#include <app/query/SearchTrackListQuery.h>
#include <app/util/Hotkeys.h>
#include <app/util/PreferenceKeys.h>

#include <boost/format.hpp>

#include "SettingsLayout.h"

using namespace musik;
using namespace musik::core::library::constants;
using namespace musik::core;
using namespace musik::box;
using namespace cursespp;
using namespace std::placeholders;

#define LABEL_HEIGHT 1
#define INPUT_HEIGHT 3
#define HOTKEY_INPUT_WIDTH 20

#define TOP(w) w->GetY()
#define BOTTOM(w) (w->GetY() + w->GetHeight())
#define LEFT(w) w->GetX()
#define RIGHT(w) (w->GetX() + w->GetWidth())

#define CREATE_CHECKBOX(checkbox, caption) \
    checkbox.reset(new cursespp::Checkbox()); \
    checkbox->SetText(caption); \
    checkbox->CheckChanged.connect(this, &SettingsLayout::OnCheckboxChanged);

using EntryPtr = IScrollAdapter::EntryPtr;

static bool showDotfiles = false;

SettingsLayout::SettingsLayout(musik::core::LibraryPtr library)
: LayoutBase()
, library(library)
, indexer(library->Indexer()) {
    this->prefs = Preferences::ForComponent(core::prefs::components::Settings);
    this->indexer->PathsUpdated.connect(this, &SettingsLayout::RefreshAddedPaths);
    this->InitializeWindows();
}

SettingsLayout::~SettingsLayout() {
}

void SettingsLayout::OnCheckboxChanged(cursespp::Checkbox* cb, bool checked) {
    if (cb == removeCheckbox.get()) {
        this->prefs->SetBool(core::prefs::keys::RemoveMissingFiles, checked);
        this->prefs->Save();
    }
    else if (cb == dotfileCheckbox.get()) {
        showDotfiles = !showDotfiles;
        this->browseAdapter.SetDotfilesVisible(showDotfiles);
        this->browseList->OnAdapterChanged();
    }
    else if (cb == focusShortcutsCheckbox.get()) {
        this->prefs->SetBool(box::prefs::keys::EscFocusesShortcuts, checked);
        this->prefs->Save();
    }
    else if (cb == customColorsCheckbox.get()) {
        this->prefs->SetBool(box::prefs::keys::DisableCustomColors, checked);
        this->prefs->Save();
    }
}

void SettingsLayout::Layout() {
    int x = this->GetX(), y = this->GetY();
    int cx = this->GetWidth(), cy = this->GetHeight();

    int startY = 0;
    int leftX = 0;
    int leftWidth = cx / 3; /* 1/3 width */
    int rightX = leftWidth;
    int rightWidth = cx - rightX; /* remainder (~2/3) */

    this->browseLabel->MoveAndResize(leftX + 1, startY, leftWidth - 1, LABEL_HEIGHT);
    this->addedPathsLabel->MoveAndResize(rightX + 1, startY, rightWidth - 1, LABEL_HEIGHT);

    int pathListsY = BOTTOM(this->browseLabel);
    int pathsHeight = (cy - pathListsY) / 2;

    this->browseList->MoveAndResize(leftX, pathListsY, leftWidth, pathsHeight);
    this->addedPathsList->MoveAndResize(rightX, pathListsY, rightWidth, pathsHeight);

    this->dotfileCheckbox->MoveAndResize(1, BOTTOM(this->browseList), cx - 1, LABEL_HEIGHT);
    this->removeCheckbox->MoveAndResize(1, BOTTOM(this->dotfileCheckbox), cx - 1, LABEL_HEIGHT);
    this->focusShortcutsCheckbox->MoveAndResize(1, BOTTOM(this->removeCheckbox), cx - 1, LABEL_HEIGHT);
    this->customColorsCheckbox->MoveAndResize(1, BOTTOM(this->focusShortcutsCheckbox), cx - 1, LABEL_HEIGHT);

    this->hotkeyLabel->MoveAndResize(
        1,
        BOTTOM(this->customColorsCheckbox) + 2,
        this->hotkeyLabel->Length(),
        LABEL_HEIGHT);

    this->hotkeyInput->MoveAndResize(
        RIGHT(this->hotkeyLabel),
        BOTTOM(this->customColorsCheckbox) + 1,
        HOTKEY_INPUT_WIDTH,
        INPUT_HEIGHT);
}

void SettingsLayout::RefreshAddedPaths() {
    this->addedPathsAdapter.Clear();

    std::vector<std::string> paths;
    this->indexer->GetPaths(paths);

    for (size_t i = 0; i < paths.size(); i++) {
        auto v = paths.at(i);
        auto e = EntryPtr(new SingleLineEntry(v));
        this->addedPathsAdapter.AddEntry(e);
    }

    this->addedPathsList->OnAdapterChanged();
}

int64 SettingsLayout::ListItemDecorator(
    ScrollableWindow* scrollable,
    size_t index,
    size_t line,
    IScrollAdapter::EntryPtr entry)
{
    if (scrollable == this->addedPathsList.get() ||
        scrollable == this->browseList.get())
    {
         ListWindow* lw = static_cast<ListWindow*>(scrollable);
         if (lw->GetSelectedIndex() == index) {
             return COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM);
         }
    }
    return -1;
}

void SettingsLayout::InitializeWindows() {
    this->SetFrameVisible(false);

    this->browseLabel.reset(new TextLabel());
    this->browseLabel->SetText("browse (SPACE to add)", text::AlignLeft);

    this->addedPathsLabel.reset(new TextLabel());
    this->addedPathsLabel->SetText("indexed paths (BACKSPACE to remove)", text::AlignLeft);

    this->addedPathsList.reset(new cursespp::ListWindow(&this->addedPathsAdapter));
    this->browseList.reset(new cursespp::ListWindow(&this->browseAdapter));

    ScrollAdapterBase::ItemDecorator decorator =
        std::bind(
            &SettingsLayout::ListItemDecorator,
            this,
            std::placeholders::_1,
            std::placeholders::_2,
            std::placeholders::_3,
            std::placeholders::_4);

    this->addedPathsAdapter.SetItemDecorator(decorator);
    this->browseAdapter.SetItemDecorator(decorator);

    CREATE_CHECKBOX(this->dotfileCheckbox, "show dotfiles in directory browser");
    CREATE_CHECKBOX(this->removeCheckbox, "remove missing files from library");
    CREATE_CHECKBOX(this->focusShortcutsCheckbox, "esc key focuses shortcuts bar");
    CREATE_CHECKBOX(this->customColorsCheckbox, "disable custom colors (requires restart)");

    this->hotkeyLabel.reset(new TextLabel());
    this->hotkeyLabel->SetText("hotkey tester: ");
    this->hotkeyInput.reset(new TextInput(IInput::InputRaw));

    this->browseList->SetFocusOrder(0);
    this->addedPathsList->SetFocusOrder(1);
    this->dotfileCheckbox->SetFocusOrder(2);
    this->removeCheckbox->SetFocusOrder(3);
    this->focusShortcutsCheckbox->SetFocusOrder(4);
    this->customColorsCheckbox->SetFocusOrder(5);
    this->hotkeyInput->SetFocusOrder(6);

    this->AddWindow(this->browseLabel);
    this->AddWindow(this->addedPathsLabel);
    this->AddWindow(this->browseList);
    this->AddWindow(this->addedPathsList);
    this->AddWindow(this->dotfileCheckbox);
    this->AddWindow(this->removeCheckbox);
    this->AddWindow(this->focusShortcutsCheckbox);
    this->AddWindow(this->customColorsCheckbox);
    this->AddWindow(this->hotkeyLabel);
    this->AddWindow(this->hotkeyInput);
}

void SettingsLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) {
    if (shortcuts) {
        shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateSettings), "settings");
        shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateLibrary), "library");
        shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateConsole), "console");
        shortcuts->AddShortcut("^D", "quit");
        shortcuts->SetActive(Hotkeys::Get(Hotkeys::NavigateSettings));
    }
}

void SettingsLayout::OnVisibilityChanged(bool visible) {
    LayoutBase::OnVisibilityChanged(visible);

    if (visible) {
        this->RefreshAddedPaths();
        this->LoadPreferences();
        this->CheckShowFirstRunDialog();
    }
}

void SettingsLayout::CheckShowFirstRunDialog() {
    if (!this->prefs->GetBool(box::prefs::keys::FirstRunSettingsDisplayed)) {
        std::shared_ptr<DialogOverlay> dialog(new DialogOverlay());

        dialog->SetTitle("welcome to musikbox!")
            .SetMessage(boost::str(boost::format(
                "add some directories that contain music files, "
                "then press '%s' to show the library view and start listening!\n\n"
                "for troubleshooting, press '%s' to enter the console view.\n\n"
                "other keyboard shorcuts are displayed in the command bar at the "
                "bottom of the screen. toggle command mode by pressing 'ESC'.\n\n"
                "select 'ok' to get started.")
                    % Hotkeys::Get(Hotkeys::NavigateLibrary)
                    % Hotkeys::Get(Hotkeys::NavigateConsole)));

        dialog->AddButton(
            "KEY_ENTER",
            "ENTER",
            "ok",
            [this](std::string key) {
                this->prefs->SetBool(box::prefs::keys::FirstRunSettingsDisplayed, true);
            });

        App::Overlays().Push(dialog);
    }
}

void SettingsLayout::LoadPreferences() {
    this->removeCheckbox->SetChecked(this->prefs->GetBool(core::prefs::keys::RemoveMissingFiles, true));
    this->focusShortcutsCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::EscFocusesShortcuts, true));
    this->customColorsCheckbox->SetChecked(this->prefs->GetBool(box::prefs::keys::DisableCustomColors));
}

void SettingsLayout::AddSelectedDirectory() {
    size_t index = this->browseList->GetSelectedIndex();
    std::string path = this->browseAdapter.GetFullPathAt(index);

    if (path.size()) {
        this->indexer->AddPath(path);
    }
}

void SettingsLayout::RemoveSelectedDirectory() {
    std::vector<std::string> paths;
    this->indexer->GetPaths(paths);
    size_t index = this->addedPathsList->GetSelectedIndex();
    this->indexer->RemovePath(paths.at(index));
}

void SettingsLayout::DrillIntoSelectedDirectory() {
    this->browseAdapter.Select(this->browseList->GetSelectedIndex());
    this->browseList->SetSelectedIndex(0);
    this->browseList->OnAdapterChanged();
}

bool SettingsLayout::KeyPress(const std::string& key) {
    if (key == "KEY_ENTER") {
        if (this->GetFocus() == this->browseList) {
            this->DrillIntoSelectedDirectory();
            return true;
        }
    }
    else if (key == " ") {
        if (this->GetFocus() == this->browseList) {
            this->AddSelectedDirectory();
            return true;
        }
    }
    else if (key == "KEY_BACKSPACE") { /* backspace */
        if (this->GetFocus() == this->addedPathsList) {
            this->RemoveSelectedDirectory();
            return true;
        }
    }

    return LayoutBase::KeyPress(key);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE 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 OWNER 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 <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		if (m_num_connecting == 0) m_timer.cancel(ec);
		m_abort = true;

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		// we don't want to call the timeout callback while we're locked
		// since that is a recipie for dead-locks
		l.unlock();

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				mutex_t::scoped_lock ll(m_mutex);
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_timeout();
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		// if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		l.unlock();

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}

	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);
		if (e && m_num_connecting == 0)
			return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect(l);
	}

	void connection_queue::on_try_connect()
	{
		mutex_t::scoped_lock l(m_mutex);
		try_connect(l);
	}
}

<commit_msg>revert shutdown hang fix<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE 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 OWNER 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 <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		if (m_num_connecting == 0) m_timer.cancel(ec);
		m_abort = true;

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		// we don't want to call the timeout callback while we're locked
		// since that is a recipie for dead-locks
		l.unlock();

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				mutex_t::scoped_lock ll(m_mutex);
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_timeout();
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		// if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			if (m_num_connecting == m_queue.size()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		l.unlock();

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}

	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect(l);
	}

	void connection_queue::on_try_connect()
	{
		mutex_t::scoped_lock l(m_mutex);
		try_connect(l);
	}
}

<|endoftext|>


<commit_before>//===-- Timer.cpp - Interval Timing Support -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file Interval Timing implementation.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Timer.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

// This ugly hack is brought to you courtesy of constructor/destructor ordering
// being unspecified by C++.  Basically the problem is that a Statistic object
// gets destroyed, which ends up calling 'GetLibSupportInfoOutputFile()'
// (below), which calls this function.  LibSupportInfoOutputFilename used to be
// a global variable, but sometimes it would get destroyed before the Statistic,
// causing havoc to ensue.  We "fix" this by creating the string the first time
// it is needed and never destroying it.
static ManagedStatic<std::string> LibSupportInfoOutputFilename;
static std::string &getLibSupportInfoOutputFilename() {
  return *LibSupportInfoOutputFilename;
}

static ManagedStatic<sys::SmartMutex<true> > TimerLock;

namespace {
  static cl::opt<bool>
  TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
                                      "tracking (this may be slow)"),
             cl::Hidden);

  static cl::opt<std::string, true>
  InfoOutputFilename("info-output-file", cl::value_desc("filename"),
                     cl::desc("File to append -stats and -timer output to"),
                   cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
}

std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() {
  const std::string &OutputFilename = getLibSupportInfoOutputFilename();
  if (OutputFilename.empty())
    return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
  if (OutputFilename == "-")
    return llvm::make_unique<raw_fd_ostream>(1, false); // stdout.

  // Append mode is used because the info output file is opened and closed
  // each time -stats or -time-passes wants to print output to it. To
  // compensate for this, the test-suite Makefiles have code to delete the
  // info output file before running commands which write to it.
  std::error_code EC;
  auto Result = llvm::make_unique<raw_fd_ostream>(
      OutputFilename, EC, sys::fs::F_Append | sys::fs::F_Text);
  if (!EC)
    return Result;

  errs() << "Error opening info-output-file '"
    << OutputFilename << " for appending!\n";
  return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
}

namespace {
struct CreateDefaultTimerGroup {
  static void *call() {
    return new TimerGroup("misc", "Miscellaneous Ungrouped Timers");
  }
};
} // namespace
static ManagedStatic<TimerGroup, CreateDefaultTimerGroup> DefaultTimerGroup;
static TimerGroup *getDefaultTimerGroup() { return &*DefaultTimerGroup; }

//===----------------------------------------------------------------------===//
// Timer Implementation
//===----------------------------------------------------------------------===//

void Timer::init(StringRef Name, StringRef Description) {
  init(Name, Description, *getDefaultTimerGroup());
}

void Timer::init(StringRef Name, StringRef Description, TimerGroup &tg) {
  assert(!TG && "Timer already initialized");
  this->Name.assign(Name.begin(), Name.end());
  this->Description.assign(Description.begin(), Description.end());
  Running = Triggered = false;
  TG = &tg;
  TG->addTimer(*this);
}

Timer::~Timer() {
  if (!TG) return;  // Never initialized, or already cleared.
  TG->removeTimer(*this);
}

static inline size_t getMemUsage() {
  if (!TrackSpace) return 0;
  return sys::Process::GetMallocUsage();
}

TimeRecord TimeRecord::getCurrentTime(bool Start) {
  using Seconds = std::chrono::duration<double, std::ratio<1>>;
  TimeRecord Result;
  sys::TimePoint<> now;
  std::chrono::nanoseconds user, sys;

  if (Start) {
    Result.MemUsed = getMemUsage();
    sys::Process::GetTimeUsage(now, user, sys);
  } else {
    sys::Process::GetTimeUsage(now, user, sys);
    Result.MemUsed = getMemUsage();
  }

  Result.WallTime = Seconds(now.time_since_epoch()).count();
  Result.UserTime = Seconds(user).count();
  Result.SystemTime = Seconds(sys).count();
  return Result;
}

void Timer::startTimer() {
  assert(!Running && "Cannot start a running timer");
  Running = Triggered = true;
  StartTime = TimeRecord::getCurrentTime(true);
}

void Timer::stopTimer() {
  assert(Running && "Cannot stop a paused timer");
  Running = false;
  Time += TimeRecord::getCurrentTime(false);
  Time -= StartTime;
}

void Timer::clear() {
  Running = Triggered = false;
  Time = StartTime = TimeRecord();
}

static void printVal(double Val, double Total, raw_ostream &OS) {
  if (Total < 1e-7)   // Avoid dividing by zero.
    OS << "        -----     ";
  else
    OS << format("  %7.4f (%5.1f%%)", Val, Val*100/Total);
}

void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
  if (Total.getUserTime())
    printVal(getUserTime(), Total.getUserTime(), OS);
  if (Total.getSystemTime())
    printVal(getSystemTime(), Total.getSystemTime(), OS);
  if (Total.getProcessTime())
    printVal(getProcessTime(), Total.getProcessTime(), OS);
  printVal(getWallTime(), Total.getWallTime(), OS);

  OS << "  ";

  if (Total.getMemUsed())
    OS << format("%9" PRId64 "  ", (int64_t)getMemUsed());
}

//===----------------------------------------------------------------------===//
//   NamedRegionTimer Implementation
//===----------------------------------------------------------------------===//

namespace {

typedef StringMap<Timer> Name2TimerMap;

class Name2PairMap {
  StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map;
public:
  ~Name2PairMap() {
    for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
         I = Map.begin(), E = Map.end(); I != E; ++I)
      delete I->second.first;
  }

  Timer &get(StringRef Name, StringRef Description, StringRef GroupName,
             StringRef GroupDescription) {
    sys::SmartScopedLock<true> L(*TimerLock);

    std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];

    if (!GroupEntry.first)
      GroupEntry.first = new TimerGroup(GroupName, GroupDescription);

    Timer &T = GroupEntry.second[Name];
    if (!T.isInitialized())
      T.init(Name, Description, *GroupEntry.first);
    return T;
  }
};

}

static ManagedStatic<Name2PairMap> NamedGroupedTimers;

NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description,
                                   StringRef GroupName,
                                   StringRef GroupDescription, bool Enabled)
  : TimeRegion(!Enabled ? nullptr
                 : &NamedGroupedTimers->get(Name, Description, GroupName,
                                            GroupDescription)) {}

//===----------------------------------------------------------------------===//
//   TimerGroup Implementation
//===----------------------------------------------------------------------===//

/// This is the global list of TimerGroups, maintained by the TimerGroup
/// ctor/dtor and is protected by the TimerLock lock.
static TimerGroup *TimerGroupList = nullptr;

TimerGroup::TimerGroup(StringRef Name, StringRef Description)
  : Name(Name.begin(), Name.end()),
    Description(Description.begin(), Description.end()) {
  // Add the group to TimerGroupList.
  sys::SmartScopedLock<true> L(*TimerLock);
  if (TimerGroupList)
    TimerGroupList->Prev = &Next;
  Next = TimerGroupList;
  Prev = &TimerGroupList;
  TimerGroupList = this;
}

TimerGroup::~TimerGroup() {
  // If the timer group is destroyed before the timers it owns, accumulate and
  // print the timing data.
  while (FirstTimer)
    removeTimer(*FirstTimer);

  // Remove the group from the TimerGroupList.
  sys::SmartScopedLock<true> L(*TimerLock);
  *Prev = Next;
  if (Next)
    Next->Prev = Prev;
}

void TimerGroup::removeTimer(Timer &T) {
  sys::SmartScopedLock<true> L(*TimerLock);

  // If the timer was started, move its data to TimersToPrint.
  if (T.hasTriggered())
    TimersToPrint.emplace_back(T.Time, T.Name, T.Description);

  T.TG = nullptr;

  // Unlink the timer from our list.
  *T.Prev = T.Next;
  if (T.Next)
    T.Next->Prev = T.Prev;

  // Print the report when all timers in this group are destroyed if some of
  // them were started.
  if (FirstTimer || TimersToPrint.empty())
    return;

  std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
  PrintQueuedTimers(*OutStream);
}

void TimerGroup::addTimer(Timer &T) {
  sys::SmartScopedLock<true> L(*TimerLock);

  // Add the timer to our list.
  if (FirstTimer)
    FirstTimer->Prev = &T.Next;
  T.Next = FirstTimer;
  T.Prev = &FirstTimer;
  FirstTimer = &T;
}

void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
  // Sort the timers in descending order by amount of time taken.
  llvm::sort(TimersToPrint.begin(), TimersToPrint.end());

  TimeRecord Total;
  for (const PrintRecord &Record : TimersToPrint)
    Total += Record.Time;

  // Print out timing header.
  OS << "===" << std::string(73, '-') << "===\n";
  // Figure out how many spaces to indent TimerGroup name.
  unsigned Padding = (80-Description.length())/2;
  if (Padding > 80) Padding = 0;         // Don't allow "negative" numbers
  OS.indent(Padding) << Description << '\n';
  OS << "===" << std::string(73, '-') << "===\n";

  // If this is not an collection of ungrouped times, print the total time.
  // Ungrouped timers don't really make sense to add up.  We still print the
  // TOTAL line to make the percentages make sense.
  if (this != getDefaultTimerGroup())
    OS << format("  Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
                 Total.getProcessTime(), Total.getWallTime());
  OS << '\n';

  if (Total.getUserTime())
    OS << "   ---User Time---";
  if (Total.getSystemTime())
    OS << "   --System Time--";
  if (Total.getProcessTime())
    OS << "   --User+System--";
  OS << "   ---Wall Time---";
  if (Total.getMemUsed())
    OS << "  ---Mem---";
  OS << "  --- Name ---\n";

  // Loop through all of the timing data, printing it out.
  for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(),
                                              TimersToPrint.rend())) {
    Record.Time.print(Total, OS);
    OS << Record.Description << '\n';
  }

  Total.print(Total, OS);
  OS << "Total\n\n";
  OS.flush();

  TimersToPrint.clear();
}

void TimerGroup::prepareToPrintList() {
  // See if any of our timers were started, if so add them to TimersToPrint and
  // reset them.
  for (Timer *T = FirstTimer; T; T = T->Next) {
    if (!T->hasTriggered()) continue;
    bool WasRunning = T->isRunning();
    if (WasRunning)
      T->stopTimer();

    TimersToPrint.emplace_back(T->Time, T->Name, T->Description);

    if (WasRunning)
      T->startTimer();
  }
}

void TimerGroup::print(raw_ostream &OS) {
  sys::SmartScopedLock<true> L(*TimerLock);

  prepareToPrintList();

  // If any timers were started, print the group.
  if (!TimersToPrint.empty())
    PrintQueuedTimers(OS);
}

void TimerGroup::printAll(raw_ostream &OS) {
  sys::SmartScopedLock<true> L(*TimerLock);

  for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
    TG->print(OS);
}

void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
                                const char *suffix, double Value) {
  assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
         "TimerGroup name needs no quotes");
  assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
         "Timer name needs no quotes");
  OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value;
}

const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
  prepareToPrintList();
  for (const PrintRecord &R : TimersToPrint) {
    OS << delim;
    delim = ",\n";

    const TimeRecord &T = R.Time;
    printJSONValue(OS, R, ".wall", T.getWallTime());
    OS << delim;
    printJSONValue(OS, R, ".user", T.getUserTime());
    OS << delim;
    printJSONValue(OS, R, ".sys", T.getSystemTime());
    if (T.getMemUsed()) {
      OS << delim;
      printJSONValue(OS, R, ".mem", T.getMemUsed());
    }
  }
  TimersToPrint.clear();
  return delim;
}

const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
  sys::SmartScopedLock<true> L(*TimerLock);
  for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
    delim = TG->printJSONValues(OS, delim);
  return delim;
}

void TimerGroup::ConstructTimerLists() {
  (void)*NamedGroupedTimers;
}
<commit_msg>[Timers] TimerGroup::printJSONValue(): print doubles with no precision loss<commit_after>//===-- Timer.cpp - Interval Timing Support -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file Interval Timing implementation.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Timer.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <limits>

using namespace llvm;

// This ugly hack is brought to you courtesy of constructor/destructor ordering
// being unspecified by C++.  Basically the problem is that a Statistic object
// gets destroyed, which ends up calling 'GetLibSupportInfoOutputFile()'
// (below), which calls this function.  LibSupportInfoOutputFilename used to be
// a global variable, but sometimes it would get destroyed before the Statistic,
// causing havoc to ensue.  We "fix" this by creating the string the first time
// it is needed and never destroying it.
static ManagedStatic<std::string> LibSupportInfoOutputFilename;
static std::string &getLibSupportInfoOutputFilename() {
  return *LibSupportInfoOutputFilename;
}

static ManagedStatic<sys::SmartMutex<true> > TimerLock;

namespace {
  static cl::opt<bool>
  TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
                                      "tracking (this may be slow)"),
             cl::Hidden);

  static cl::opt<std::string, true>
  InfoOutputFilename("info-output-file", cl::value_desc("filename"),
                     cl::desc("File to append -stats and -timer output to"),
                   cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
}

std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() {
  const std::string &OutputFilename = getLibSupportInfoOutputFilename();
  if (OutputFilename.empty())
    return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
  if (OutputFilename == "-")
    return llvm::make_unique<raw_fd_ostream>(1, false); // stdout.

  // Append mode is used because the info output file is opened and closed
  // each time -stats or -time-passes wants to print output to it. To
  // compensate for this, the test-suite Makefiles have code to delete the
  // info output file before running commands which write to it.
  std::error_code EC;
  auto Result = llvm::make_unique<raw_fd_ostream>(
      OutputFilename, EC, sys::fs::F_Append | sys::fs::F_Text);
  if (!EC)
    return Result;

  errs() << "Error opening info-output-file '"
    << OutputFilename << " for appending!\n";
  return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
}

namespace {
struct CreateDefaultTimerGroup {
  static void *call() {
    return new TimerGroup("misc", "Miscellaneous Ungrouped Timers");
  }
};
} // namespace
static ManagedStatic<TimerGroup, CreateDefaultTimerGroup> DefaultTimerGroup;
static TimerGroup *getDefaultTimerGroup() { return &*DefaultTimerGroup; }

//===----------------------------------------------------------------------===//
// Timer Implementation
//===----------------------------------------------------------------------===//

void Timer::init(StringRef Name, StringRef Description) {
  init(Name, Description, *getDefaultTimerGroup());
}

void Timer::init(StringRef Name, StringRef Description, TimerGroup &tg) {
  assert(!TG && "Timer already initialized");
  this->Name.assign(Name.begin(), Name.end());
  this->Description.assign(Description.begin(), Description.end());
  Running = Triggered = false;
  TG = &tg;
  TG->addTimer(*this);
}

Timer::~Timer() {
  if (!TG) return;  // Never initialized, or already cleared.
  TG->removeTimer(*this);
}

static inline size_t getMemUsage() {
  if (!TrackSpace) return 0;
  return sys::Process::GetMallocUsage();
}

TimeRecord TimeRecord::getCurrentTime(bool Start) {
  using Seconds = std::chrono::duration<double, std::ratio<1>>;
  TimeRecord Result;
  sys::TimePoint<> now;
  std::chrono::nanoseconds user, sys;

  if (Start) {
    Result.MemUsed = getMemUsage();
    sys::Process::GetTimeUsage(now, user, sys);
  } else {
    sys::Process::GetTimeUsage(now, user, sys);
    Result.MemUsed = getMemUsage();
  }

  Result.WallTime = Seconds(now.time_since_epoch()).count();
  Result.UserTime = Seconds(user).count();
  Result.SystemTime = Seconds(sys).count();
  return Result;
}

void Timer::startTimer() {
  assert(!Running && "Cannot start a running timer");
  Running = Triggered = true;
  StartTime = TimeRecord::getCurrentTime(true);
}

void Timer::stopTimer() {
  assert(Running && "Cannot stop a paused timer");
  Running = false;
  Time += TimeRecord::getCurrentTime(false);
  Time -= StartTime;
}

void Timer::clear() {
  Running = Triggered = false;
  Time = StartTime = TimeRecord();
}

static void printVal(double Val, double Total, raw_ostream &OS) {
  if (Total < 1e-7)   // Avoid dividing by zero.
    OS << "        -----     ";
  else
    OS << format("  %7.4f (%5.1f%%)", Val, Val*100/Total);
}

void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
  if (Total.getUserTime())
    printVal(getUserTime(), Total.getUserTime(), OS);
  if (Total.getSystemTime())
    printVal(getSystemTime(), Total.getSystemTime(), OS);
  if (Total.getProcessTime())
    printVal(getProcessTime(), Total.getProcessTime(), OS);
  printVal(getWallTime(), Total.getWallTime(), OS);

  OS << "  ";

  if (Total.getMemUsed())
    OS << format("%9" PRId64 "  ", (int64_t)getMemUsed());
}

//===----------------------------------------------------------------------===//
//   NamedRegionTimer Implementation
//===----------------------------------------------------------------------===//

namespace {

typedef StringMap<Timer> Name2TimerMap;

class Name2PairMap {
  StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map;
public:
  ~Name2PairMap() {
    for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
         I = Map.begin(), E = Map.end(); I != E; ++I)
      delete I->second.first;
  }

  Timer &get(StringRef Name, StringRef Description, StringRef GroupName,
             StringRef GroupDescription) {
    sys::SmartScopedLock<true> L(*TimerLock);

    std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];

    if (!GroupEntry.first)
      GroupEntry.first = new TimerGroup(GroupName, GroupDescription);

    Timer &T = GroupEntry.second[Name];
    if (!T.isInitialized())
      T.init(Name, Description, *GroupEntry.first);
    return T;
  }
};

}

static ManagedStatic<Name2PairMap> NamedGroupedTimers;

NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description,
                                   StringRef GroupName,
                                   StringRef GroupDescription, bool Enabled)
  : TimeRegion(!Enabled ? nullptr
                 : &NamedGroupedTimers->get(Name, Description, GroupName,
                                            GroupDescription)) {}

//===----------------------------------------------------------------------===//
//   TimerGroup Implementation
//===----------------------------------------------------------------------===//

/// This is the global list of TimerGroups, maintained by the TimerGroup
/// ctor/dtor and is protected by the TimerLock lock.
static TimerGroup *TimerGroupList = nullptr;

TimerGroup::TimerGroup(StringRef Name, StringRef Description)
  : Name(Name.begin(), Name.end()),
    Description(Description.begin(), Description.end()) {
  // Add the group to TimerGroupList.
  sys::SmartScopedLock<true> L(*TimerLock);
  if (TimerGroupList)
    TimerGroupList->Prev = &Next;
  Next = TimerGroupList;
  Prev = &TimerGroupList;
  TimerGroupList = this;
}

TimerGroup::~TimerGroup() {
  // If the timer group is destroyed before the timers it owns, accumulate and
  // print the timing data.
  while (FirstTimer)
    removeTimer(*FirstTimer);

  // Remove the group from the TimerGroupList.
  sys::SmartScopedLock<true> L(*TimerLock);
  *Prev = Next;
  if (Next)
    Next->Prev = Prev;
}

void TimerGroup::removeTimer(Timer &T) {
  sys::SmartScopedLock<true> L(*TimerLock);

  // If the timer was started, move its data to TimersToPrint.
  if (T.hasTriggered())
    TimersToPrint.emplace_back(T.Time, T.Name, T.Description);

  T.TG = nullptr;

  // Unlink the timer from our list.
  *T.Prev = T.Next;
  if (T.Next)
    T.Next->Prev = T.Prev;

  // Print the report when all timers in this group are destroyed if some of
  // them were started.
  if (FirstTimer || TimersToPrint.empty())
    return;

  std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
  PrintQueuedTimers(*OutStream);
}

void TimerGroup::addTimer(Timer &T) {
  sys::SmartScopedLock<true> L(*TimerLock);

  // Add the timer to our list.
  if (FirstTimer)
    FirstTimer->Prev = &T.Next;
  T.Next = FirstTimer;
  T.Prev = &FirstTimer;
  FirstTimer = &T;
}

void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
  // Sort the timers in descending order by amount of time taken.
  llvm::sort(TimersToPrint.begin(), TimersToPrint.end());

  TimeRecord Total;
  for (const PrintRecord &Record : TimersToPrint)
    Total += Record.Time;

  // Print out timing header.
  OS << "===" << std::string(73, '-') << "===\n";
  // Figure out how many spaces to indent TimerGroup name.
  unsigned Padding = (80-Description.length())/2;
  if (Padding > 80) Padding = 0;         // Don't allow "negative" numbers
  OS.indent(Padding) << Description << '\n';
  OS << "===" << std::string(73, '-') << "===\n";

  // If this is not an collection of ungrouped times, print the total time.
  // Ungrouped timers don't really make sense to add up.  We still print the
  // TOTAL line to make the percentages make sense.
  if (this != getDefaultTimerGroup())
    OS << format("  Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
                 Total.getProcessTime(), Total.getWallTime());
  OS << '\n';

  if (Total.getUserTime())
    OS << "   ---User Time---";
  if (Total.getSystemTime())
    OS << "   --System Time--";
  if (Total.getProcessTime())
    OS << "   --User+System--";
  OS << "   ---Wall Time---";
  if (Total.getMemUsed())
    OS << "  ---Mem---";
  OS << "  --- Name ---\n";

  // Loop through all of the timing data, printing it out.
  for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(),
                                              TimersToPrint.rend())) {
    Record.Time.print(Total, OS);
    OS << Record.Description << '\n';
  }

  Total.print(Total, OS);
  OS << "Total\n\n";
  OS.flush();

  TimersToPrint.clear();
}

void TimerGroup::prepareToPrintList() {
  // See if any of our timers were started, if so add them to TimersToPrint and
  // reset them.
  for (Timer *T = FirstTimer; T; T = T->Next) {
    if (!T->hasTriggered()) continue;
    bool WasRunning = T->isRunning();
    if (WasRunning)
      T->stopTimer();

    TimersToPrint.emplace_back(T->Time, T->Name, T->Description);

    if (WasRunning)
      T->startTimer();
  }
}

void TimerGroup::print(raw_ostream &OS) {
  sys::SmartScopedLock<true> L(*TimerLock);

  prepareToPrintList();

  // If any timers were started, print the group.
  if (!TimersToPrint.empty())
    PrintQueuedTimers(OS);
}

void TimerGroup::printAll(raw_ostream &OS) {
  sys::SmartScopedLock<true> L(*TimerLock);

  for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
    TG->print(OS);
}

void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
                                const char *suffix, double Value) {
  assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
         "TimerGroup name should not need quotes");
  assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
         "Timer name should not need quotes");
  constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
  OS << "\t\"time." << Name << '.' << R.Name << suffix
     << "\": " << format("%.*e", max_digits10 - 1, Value);
}

const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
  prepareToPrintList();
  for (const PrintRecord &R : TimersToPrint) {
    OS << delim;
    delim = ",\n";

    const TimeRecord &T = R.Time;
    printJSONValue(OS, R, ".wall", T.getWallTime());
    OS << delim;
    printJSONValue(OS, R, ".user", T.getUserTime());
    OS << delim;
    printJSONValue(OS, R, ".sys", T.getSystemTime());
    if (T.getMemUsed()) {
      OS << delim;
      printJSONValue(OS, R, ".mem", T.getMemUsed());
    }
  }
  TimersToPrint.clear();
  return delim;
}

const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
  sys::SmartScopedLock<true> L(*TimerLock);
  for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
    delim = TG->printJSONValues(OS, delim);
  return delim;
}

void TimerGroup::ConstructTimerLists() {
  (void)*NamedGroupedTimers;
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
*/

#include "AliFastMuonTriggerEff.h"
#include <TFile.h>
#include <TTree.h>
#include <TROOT.h>
#include <stdlib.h>

// Debugging flag
//#define MYTRIGDEBUG

ClassImp(AliFastMuonTriggerEff);

AliFastMuonTriggerEff::AliFastMuonTriggerEff():
    AliFastResponse("Efficiency", "Muon Trigger Efficiency")
{
//
// Default constructor
//
    SetCut(kLow);
    fZones=0;
}

void AliFastMuonTriggerEff::Init()
{
//
//  Initialization
//
    printf("Initializing %s / %s", fName.Data(), fTitle.Data());
//

    fPhiMin   = -90. ;
    fPhiMax   =  90. ;
    fDphi     =   9. ;
    fThetaMin =   2. ;
    fThetaMax =   9. ;
    fDtheta   =   0.7;
    fDpt      =   0.1;

    InitTree();
}

void AliFastMuonTriggerEff::InitTree()
{
//
//  Initialize tables from tree
//
    TTree          *chain;   // pointer to the analyzed TTree or TChain
    Int_t           nSim, nZona;
    Double_t        pmin, pmax, tmin, tmax, phimin, phimax, bkg;
    Double_t        len50, hen50, leff, heff;
    Double_t        vLPt[50];
    Double_t        vHPt[50];
    Char_t file[100]="$(ALICE_ROOT)/data/vettorpara.root";
//
//  Avoid memory leak in case of reinitialization
    if(fZones!=0) {
        printf("\nWarning: reinitialization of an object of class: AliFastMuonTriggerEff\n");
        for (Int_t i=0; i<fZones; i++) {
            if(fEffLow [i])delete[] fEffLow[i];
	    if(fEffHigh[i])delete[] fEffHigh[i];
        }
	if(fEffLow) {
	    delete[] fEffLow;
	    fEffLow=0;
        }
	if(fEffHigh) {
	    delete[] fEffHigh;
	    fEffHigh=0;
        }
    }
    printf("AliFastMuonTriggerEff: Initialization\n");
    TFile *f = new TFile(file);
    if(f->IsZombie()) {
        printf("Cannot open file: %s\n",file);
        return;
    }
    f->ls();

    TTree* tree = (TTree*)gDirectory->Get("fitPar");

//
//
    chain = tree;
    chain->SetMakeClass(1);

    chain->SetBranchAddress("nSim",&nSim);
    chain->SetBranchAddress("nZona",&nZona);
    chain->SetBranchAddress("ptmin",&pmin);
    chain->SetBranchAddress("ptmax",&pmax);
    chain->SetBranchAddress("Thetamin",&tmin);
    chain->SetBranchAddress("Thetamax",&tmax);
    chain->SetBranchAddress("Phimin",&phimin);
    chain->SetBranchAddress("Phimax",&phimax);
    chain->SetBranchAddress("Bkg",&bkg);
    chain->SetBranchAddress("EffLPt",vLPt);
    chain->SetBranchAddress("EffHPt",vHPt);
    chain->SetBranchAddress("Pt0.5Low",&len50);
    chain->SetBranchAddress("Pt0.5High",&hen50);
    chain->SetBranchAddress("EffLowMax",&leff);
    chain->SetBranchAddress("EffHighMax",&heff);
//
//
    Int_t nentries = Int_t(chain->GetEntries());
    Int_t nbytes = 0, nb = 0;

// Count the number of zones of the parametrization
    Int_t nzone0=0, nzone1=0;
    for (Int_t jentry=0; jentry<nentries; jentry++) {
	nb = chain->GetEntry(jentry);
	if(bkg==0.) {
	     if(nSim==0)nzone0++;
	     if(nSim==1)nzone1++;
	}
    }

    printf("Trigger parametrisation for %d zones for Pt: 0. 5. GeV/c\n",nzone0);
    printf("and %d zones extended to 10. GeV/c\n",nzone1);
    fZones=nzone0+nzone1;
//    printf("Ciao\n");
    if(fZones<=0){
        printf("Number of zones must be greater than 0\n");
	exit(6);
    }

    fEffLow =new Float_t*[fZones];
    fEffHigh=new Float_t*[fZones];
    for (Int_t i=0; i<fZones; i++) {
        fEffLow [i]=new Float_t[50];
	fEffHigh[i]=new Float_t[50];
    }

//  Initialize look-up table to standard values
    Int_t isim, itheta, iphi;
    for (isim=0; isim<2; isim++) {
        for (itheta=0; itheta<10; itheta++) {
	    for (iphi=0; iphi<20; iphi++) {
	        fLook[isim][itheta][iphi]=0;
            }
	}
    }

//  Loading Trigger efficiencies
    Int_t myzone=0;
#ifdef MYTRIGDEBUG
            printf("Filling nSim nZona pmin pmax tmin tmax phimin phimax: ....\n");
#endif
    for (Int_t jentry=0; jentry<nentries; jentry++) {
//	Int_t ientry = LoadTree(jentry);
	nb = chain->GetEntry(jentry);
	nbytes += nb;
#ifdef MYTRIGDEBUG
       printf("Getting entry %d... ",jentry);
#endif
// For the time being it works with background 0
	if ((nSim == 0 || nSim == 1)&&bkg==0.) {
#ifdef MYTRIGDEBUG
            printf("Filling %d %d %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f: ",
	    nSim,nZona,pmin,pmax,tmin,tmax,phimin,phimax);
#endif
	    for (Int_t k = 0; k < 50; k++) {
		fEffLow [myzone][k] = vLPt[k];
		fEffHigh[myzone][k] = vHPt[k];
#ifdef MYTRIGDEBUG
		if(k<15)printf(" %5.3f",vLPt[k]);
#endif
	    }
#ifdef MYTRIGDEBUG
            printf("\n");
#endif
	    myzone++;
	    iphi=Int_t(nZona/10)-10;
	    itheta=nZona%10;
	    if(iphi<0||iphi>19||itheta<0||itheta>9) {
	        printf("The format of data file is not consistent\nwith this version of the code\n");
	        printf("This should never happen: iphi %d, itheta: %d\n",iphi,itheta);
		exit(7);
	    }
	    fLook[nSim][itheta][iphi]=myzone;
	} else {
	    printf("Skipping entry with nSim=%d, bkg=%f\n",nSim,bkg);
	}
    }
#ifdef MYTRIGDEBUG
    printf("This is the content of the LUT after first step of initialization\n");
    for(isim=0; isim<2; isim++) {
        printf("isim=%d\n",isim);
        for(iphi=0; iphi<20; iphi++) {
	    printf("iphi: %2d:",iphi);
	    for(itheta=0; itheta<10; itheta++) {
	        printf(" %4d",fLook[isim][itheta][iphi]);
            }
	    printf("\n");
	}
    }
#endif
// Filling look=up table for the zones where the extended simulation does
// not exists
    for(iphi=0; iphi<20; iphi++) {
    	for(itheta=0; itheta<10; itheta++) {
	    if(fLook[0][itheta][iphi]==0) {
	        printf("Missing entry isim=%d itheta=%d iphi=%d\n",isim,itheta,iphi);
		exit(8);
	    }
	    if(fLook[0][itheta][iphi]<0||fLook[0][itheta][iphi]>fZones) {
	        printf("Problem with entry isim=%d itheta=%d iphi=%d\n",isim,itheta,iphi);
		exit(9);
	    }
	    if(fLook[1][itheta][iphi]==0) {
                 fLook[1][itheta][iphi]=-fLook[0][itheta][iphi];
	    }
	}
    }
#ifdef MYTRIGDEBUG
    for(isim=0; isim<2; isim++) {
        printf("isim=%d\n",isim);
        for(iphi=0; iphi<20; iphi++) {
	    printf("iphi: %2d:",iphi);
	    for(itheta=0; itheta<10; itheta++) {
	        printf(" %4d",fLook[isim][itheta][iphi]);
            }
	    printf("\n");
	}
    }
        for(iphi=0; iphi<20; iphi++) {
	    for(itheta=0; itheta<10; itheta++) {
    for(isim=0; isim<2; isim++) {
	        printf("%d %2d %2d %4d:",isim,iphi,itheta,fLook[isim][itheta][iphi]);
		if(fLook[isim][itheta][iphi]>0) {
		    myzone=fLook[isim][itheta][iphi]-1;
		    for(Int_t ipt=0; ipt<20; ipt++) {
		        //printf(" %5.3f",fEffLow[myzone][ipt]);
			printf(" %5.3f",fEffHigh[myzone][ipt]);
		    }
		    printf(" ...");
		    for(Int_t ipt=40; ipt<50; ipt++) {
		        //printf(" %5.3f",fEffLow[myzone][ipt]);
			printf(" %5.3f",fEffHigh[myzone][ipt]);
		    }
		}
		printf("\n");
            }
	}
    }
#endif
    f->Close();
}

void AliFastMuonTriggerEff::Evaluate(Float_t charge, Float_t pt,
                Float_t theta, Float_t phi,Float_t& effLow, Float_t& effHigh)
{
//
//  Trigger efficiency for pt, theta, phi (low and high cut)
//
    effLow=0.;
    effHigh=0.;
    if(fZones==0) {
        printf("Call to uninitialized object of class: AliFastMuonTriggerEff\n");
	return;
    }
    if(pt<0) {
        printf("Warning: pt: %f < 0. GeV/c\n",pt);
	return;
    }
    Int_t iPt   = Int_t(pt/fDpt)%50;
    Int_t iSim  = Int_t(pt/fDpt)/50;
    Int_t iPhi  = Int_t((phi-fPhiMin)/fDphi);
    if(phi<fPhiMin)iPhi=iPhi-1;
    Int_t iTheta = Int_t((theta-fThetaMin)/fDtheta);
#ifdef MYTRIGDEBUG
    printf("iSim iPt iTheta iPhi: %d %d %d %d\n",iSim,iPt,iTheta,iPhi);
#endif
    iPhi=iPhi-40*(iPhi/40);
#ifdef MYTRIGDEBUG
    printf("1: iPhi converted to: %d for angle equivalence\n",iPhi);
#endif
    if(iPhi<0)iPhi=-iPhi-1;
    if(iPhi>19)iPhi=39-iPhi;
#ifdef MYTRIGDEBUG
    printf("2: iPhi converted to: %d for the symmetry of the spectrometer\n",iPhi);
#endif
    if(charge==1.){
    } else if(charge==-1.) {
    iPhi=19-iPhi;
#ifdef MYTRIGDEBUG
    printf("3: iPhi converted to: %d for charge symmetry\n",iPhi);
#endif
    } else {
        printf("Warning: not understand charge: %f\n",charge);
        return;
    }
    if(iTheta<0||iTheta>9) {
        printf("Warning: theta: %f outside acceptance\n",theta);
        return;
    }
    if(iPt<0) {
        printf("Warning: what do you mean with pt: %f <0?\n",pt);
	return;
    }
    if(iSim>=fSim) {
        iSim=fSim-1;
	iPt=49;
#ifdef MYTRIGDEBUG
    printf("4: iSim iPt converted to: %d %d (last zone)\n",iSim,iPt);
#endif
    }
    Int_t iLook=fLook[iSim][iTheta][iPhi];
    if(iLook<0) {
#ifdef MYTRIGDEBUG
    printf("5: iLook iPt: %d %d converted to: ",iLook,iPt);
#endif
        iLook=-iLook-1;
	iPt=49;
#ifdef MYTRIGDEBUG
    printf("%d %d from look up table contents\n",iLook,iPt);
#endif
    } else {
        iLook=iLook-1;
    }
    effLow=fEffLow[iLook][iPt];
    effHigh=fEffHigh[iLook][iPt];
#ifdef MYTRIGDEBUG
    printf("6: charge, iSim, iTheta, iPhi, iPt: %f %d %d %d %d effLow: %f, effHigh: %f\n",
               charge,iSim,iTheta,iPhi,iPt,effLow,effHigh);
#endif

    //fEffLow [iPhi][iTheta][iPt];
    //fEffHigh[iPhi][iTheta][iPt];
}

Float_t AliFastMuonTriggerEff::Evaluate(Float_t charge, Float_t pt,
                   Float_t theta, Float_t phi)
{
    //
    // Trigger efficiency for pt, theta, phi depending of fCut
    //
    if(fZones==0) {
        printf("Call to uninitialized object of class: AliFastMuonTriggerEff\n");
	return 0.;
    }
    Float_t eff;
    Float_t effLow, effHigh;

    Evaluate(charge,pt,theta,phi,effLow,effHigh);
    if (fCut == kLow)
	eff  = effLow;
    else
	eff  = effHigh;

    return eff;
}
<commit_msg>Corrected path for vettotpara.root<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/*
$Log$
Revision 1.1  2003/01/06 10:13:09  morsch
First commit.

*/

#include "AliFastMuonTriggerEff.h"
#include <TFile.h>
#include <TTree.h>
#include <TROOT.h>
#include <stdlib.h>

// Debugging flag
//#define MYTRIGDEBUG

ClassImp(AliFastMuonTriggerEff);

AliFastMuonTriggerEff::AliFastMuonTriggerEff():
    AliFastResponse("Efficiency", "Muon Trigger Efficiency")
{
//
// Default constructor
//
    SetCut(kLow);
    fZones=0;
}

void AliFastMuonTriggerEff::Init()
{
//
//  Initialization
//
    printf("Initializing %s / %s", fName.Data(), fTitle.Data());
//

    fPhiMin   = -90. ;
    fPhiMax   =  90. ;
    fDphi     =   9. ;
    fThetaMin =   2. ;
    fThetaMax =   9. ;
    fDtheta   =   0.7;
    fDpt      =   0.1;

    InitTree();
}

void AliFastMuonTriggerEff::InitTree()
{
//
//  Initialize tables from tree
//
    TTree          *chain;   // pointer to the analyzed TTree or TChain
    Int_t           nSim, nZona;
    Double_t        pmin, pmax, tmin, tmax, phimin, phimax, bkg;
    Double_t        len50, hen50, leff, heff;
    Double_t        vLPt[50];
    Double_t        vHPt[50];
    Char_t file[100]="$(ALICE_ROOT)/FASTSIM/data/vettorpara.root";
//
//  Avoid memory leak in case of reinitialization
    if(fZones!=0) {
        printf("\nWarning: reinitialization of an object of class: AliFastMuonTriggerEff\n");
        for (Int_t i=0; i<fZones; i++) {
            if(fEffLow [i])delete[] fEffLow[i];
	    if(fEffHigh[i])delete[] fEffHigh[i];
        }
	if(fEffLow) {
	    delete[] fEffLow;
	    fEffLow=0;
        }
	if(fEffHigh) {
	    delete[] fEffHigh;
	    fEffHigh=0;
        }
    }
    printf("AliFastMuonTriggerEff: Initialization\n");
    TFile *f = new TFile(file);
    if(f->IsZombie()) {
        printf("Cannot open file: %s\n",file);
        return;
    }
    f->ls();

    TTree* tree = (TTree*)gDirectory->Get("fitPar");

//
//
    chain = tree;
    chain->SetMakeClass(1);

    chain->SetBranchAddress("nSim",&nSim);
    chain->SetBranchAddress("nZona",&nZona);
    chain->SetBranchAddress("ptmin",&pmin);
    chain->SetBranchAddress("ptmax",&pmax);
    chain->SetBranchAddress("Thetamin",&tmin);
    chain->SetBranchAddress("Thetamax",&tmax);
    chain->SetBranchAddress("Phimin",&phimin);
    chain->SetBranchAddress("Phimax",&phimax);
    chain->SetBranchAddress("Bkg",&bkg);
    chain->SetBranchAddress("EffLPt",vLPt);
    chain->SetBranchAddress("EffHPt",vHPt);
    chain->SetBranchAddress("Pt0.5Low",&len50);
    chain->SetBranchAddress("Pt0.5High",&hen50);
    chain->SetBranchAddress("EffLowMax",&leff);
    chain->SetBranchAddress("EffHighMax",&heff);
//
//
    Int_t nentries = Int_t(chain->GetEntries());
    Int_t nbytes = 0, nb = 0;

// Count the number of zones of the parametrization
    Int_t nzone0=0, nzone1=0;
    for (Int_t jentry=0; jentry<nentries; jentry++) {
	nb = chain->GetEntry(jentry);
	if(bkg==0.) {
	     if(nSim==0)nzone0++;
	     if(nSim==1)nzone1++;
	}
    }

    printf("Trigger parametrisation for %d zones for Pt: 0. 5. GeV/c\n",nzone0);
    printf("and %d zones extended to 10. GeV/c\n",nzone1);
    fZones=nzone0+nzone1;
//    printf("Ciao\n");
    if(fZones<=0){
        printf("Number of zones must be greater than 0\n");
	exit(6);
    }

    fEffLow =new Float_t*[fZones];
    fEffHigh=new Float_t*[fZones];
    for (Int_t i=0; i<fZones; i++) {
        fEffLow [i]=new Float_t[50];
	fEffHigh[i]=new Float_t[50];
    }

//  Initialize look-up table to standard values
    Int_t isim, itheta, iphi;
    for (isim=0; isim<2; isim++) {
        for (itheta=0; itheta<10; itheta++) {
	    for (iphi=0; iphi<20; iphi++) {
	        fLook[isim][itheta][iphi]=0;
            }
	}
    }

//  Loading Trigger efficiencies
    Int_t myzone=0;
#ifdef MYTRIGDEBUG
            printf("Filling nSim nZona pmin pmax tmin tmax phimin phimax: ....\n");
#endif
    for (Int_t jentry=0; jentry<nentries; jentry++) {
//	Int_t ientry = LoadTree(jentry);
	nb = chain->GetEntry(jentry);
	nbytes += nb;
#ifdef MYTRIGDEBUG
       printf("Getting entry %d... ",jentry);
#endif
// For the time being it works with background 0
	if ((nSim == 0 || nSim == 1)&&bkg==0.) {
#ifdef MYTRIGDEBUG
            printf("Filling %d %d %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f: ",
	    nSim,nZona,pmin,pmax,tmin,tmax,phimin,phimax);
#endif
	    for (Int_t k = 0; k < 50; k++) {
		fEffLow [myzone][k] = vLPt[k];
		fEffHigh[myzone][k] = vHPt[k];
#ifdef MYTRIGDEBUG
		if(k<15)printf(" %5.3f",vLPt[k]);
#endif
	    }
#ifdef MYTRIGDEBUG
            printf("\n");
#endif
	    myzone++;
	    iphi=Int_t(nZona/10)-10;
	    itheta=nZona%10;
	    if(iphi<0||iphi>19||itheta<0||itheta>9) {
	        printf("The format of data file is not consistent\nwith this version of the code\n");
	        printf("This should never happen: iphi %d, itheta: %d\n",iphi,itheta);
		exit(7);
	    }
	    fLook[nSim][itheta][iphi]=myzone;
	} else {
	    printf("Skipping entry with nSim=%d, bkg=%f\n",nSim,bkg);
	}
    }
#ifdef MYTRIGDEBUG
    printf("This is the content of the LUT after first step of initialization\n");
    for(isim=0; isim<2; isim++) {
        printf("isim=%d\n",isim);
        for(iphi=0; iphi<20; iphi++) {
	    printf("iphi: %2d:",iphi);
	    for(itheta=0; itheta<10; itheta++) {
	        printf(" %4d",fLook[isim][itheta][iphi]);
            }
	    printf("\n");
	}
    }
#endif
// Filling look=up table for the zones where the extended simulation does
// not exists
    for(iphi=0; iphi<20; iphi++) {
    	for(itheta=0; itheta<10; itheta++) {
	    if(fLook[0][itheta][iphi]==0) {
	        printf("Missing entry isim=%d itheta=%d iphi=%d\n",isim,itheta,iphi);
		exit(8);
	    }
	    if(fLook[0][itheta][iphi]<0||fLook[0][itheta][iphi]>fZones) {
	        printf("Problem with entry isim=%d itheta=%d iphi=%d\n",isim,itheta,iphi);
		exit(9);
	    }
	    if(fLook[1][itheta][iphi]==0) {
                 fLook[1][itheta][iphi]=-fLook[0][itheta][iphi];
	    }
	}
    }
#ifdef MYTRIGDEBUG
    for(isim=0; isim<2; isim++) {
        printf("isim=%d\n",isim);
        for(iphi=0; iphi<20; iphi++) {
	    printf("iphi: %2d:",iphi);
	    for(itheta=0; itheta<10; itheta++) {
	        printf(" %4d",fLook[isim][itheta][iphi]);
            }
	    printf("\n");
	}
    }
        for(iphi=0; iphi<20; iphi++) {
	    for(itheta=0; itheta<10; itheta++) {
    for(isim=0; isim<2; isim++) {
	        printf("%d %2d %2d %4d:",isim,iphi,itheta,fLook[isim][itheta][iphi]);
		if(fLook[isim][itheta][iphi]>0) {
		    myzone=fLook[isim][itheta][iphi]-1;
		    for(Int_t ipt=0; ipt<20; ipt++) {
		        //printf(" %5.3f",fEffLow[myzone][ipt]);
			printf(" %5.3f",fEffHigh[myzone][ipt]);
		    }
		    printf(" ...");
		    for(Int_t ipt=40; ipt<50; ipt++) {
		        //printf(" %5.3f",fEffLow[myzone][ipt]);
			printf(" %5.3f",fEffHigh[myzone][ipt]);
		    }
		}
		printf("\n");
            }
	}
    }
#endif
    f->Close();
}

void AliFastMuonTriggerEff::Evaluate(Float_t charge, Float_t pt,
                Float_t theta, Float_t phi,Float_t& effLow, Float_t& effHigh)
{
//
//  Trigger efficiency for pt, theta, phi (low and high cut)
//
    effLow=0.;
    effHigh=0.;
    if(fZones==0) {
        printf("Call to uninitialized object of class: AliFastMuonTriggerEff\n");
	return;
    }
    if(pt<0) {
        printf("Warning: pt: %f < 0. GeV/c\n",pt);
	return;
    }
    Int_t iPt   = Int_t(pt/fDpt)%50;
    Int_t iSim  = Int_t(pt/fDpt)/50;
    Int_t iPhi  = Int_t((phi-fPhiMin)/fDphi);
    if(phi<fPhiMin)iPhi=iPhi-1;
    Int_t iTheta = Int_t((theta-fThetaMin)/fDtheta);
#ifdef MYTRIGDEBUG
    printf("iSim iPt iTheta iPhi: %d %d %d %d\n",iSim,iPt,iTheta,iPhi);
#endif
    iPhi=iPhi-40*(iPhi/40);
#ifdef MYTRIGDEBUG
    printf("1: iPhi converted to: %d for angle equivalence\n",iPhi);
#endif
    if(iPhi<0)iPhi=-iPhi-1;
    if(iPhi>19)iPhi=39-iPhi;
#ifdef MYTRIGDEBUG
    printf("2: iPhi converted to: %d for the symmetry of the spectrometer\n",iPhi);
#endif
    if(charge==1.){
    } else if(charge==-1.) {
    iPhi=19-iPhi;
#ifdef MYTRIGDEBUG
    printf("3: iPhi converted to: %d for charge symmetry\n",iPhi);
#endif
    } else {
        printf("Warning: not understand charge: %f\n",charge);
        return;
    }
    if(iTheta<0||iTheta>9) {
        printf("Warning: theta: %f outside acceptance\n",theta);
        return;
    }
    if(iPt<0) {
        printf("Warning: what do you mean with pt: %f <0?\n",pt);
	return;
    }
    if(iSim>=fSim) {
        iSim=fSim-1;
	iPt=49;
#ifdef MYTRIGDEBUG
    printf("4: iSim iPt converted to: %d %d (last zone)\n",iSim,iPt);
#endif
    }
    Int_t iLook=fLook[iSim][iTheta][iPhi];
    if(iLook<0) {
#ifdef MYTRIGDEBUG
    printf("5: iLook iPt: %d %d converted to: ",iLook,iPt);
#endif
        iLook=-iLook-1;
	iPt=49;
#ifdef MYTRIGDEBUG
    printf("%d %d from look up table contents\n",iLook,iPt);
#endif
    } else {
        iLook=iLook-1;
    }
    effLow=fEffLow[iLook][iPt];
    effHigh=fEffHigh[iLook][iPt];
#ifdef MYTRIGDEBUG
    printf("6: charge, iSim, iTheta, iPhi, iPt: %f %d %d %d %d effLow: %f, effHigh: %f\n",
               charge,iSim,iTheta,iPhi,iPt,effLow,effHigh);
#endif

    //fEffLow [iPhi][iTheta][iPt];
    //fEffHigh[iPhi][iTheta][iPt];
}

Float_t AliFastMuonTriggerEff::Evaluate(Float_t charge, Float_t pt,
                   Float_t theta, Float_t phi)
{
    //
    // Trigger efficiency for pt, theta, phi depending of fCut
    //
    if(fZones==0) {
        printf("Call to uninitialized object of class: AliFastMuonTriggerEff\n");
	return 0.;
    }
    Float_t eff;
    Float_t effLow, effHigh;

    Evaluate(charge,pt,theta,phi,effLow,effHigh);
    if (fCut == kLow)
	eff  = effLow;
    else
	eff  = effHigh;

    return eff;
}
<|endoftext|>