<commit_before>#include "client.hh"

#include "context.hh"
#include "register_manager.hh"

#include <unordered_map>

namespace Kakoune
{

extern std::unordered_map<Key, std::function<void (Context& context)>> keymap;

class Client::NormalMode : public Client::Mode
{
public:
    NormalMode(Client& client)
        : Client::Mode(client)
    {
    }

    void on_key(const Key& key, Context& context) override
    {
        if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
            m_count = m_count * 10 + key.key - '0';
        else
        {
            auto it = keymap.find(key);
            if (it != keymap.end())
            {
                context.numeric_param(m_count);
                // it's important to do that before calling the command,
                // as we may die during the command execution.
                m_count = 0;
                it->second(context);
            }
            else
                m_count = 0;
        }
    }

private:
    int m_count = 0;
};

class Client::MenuMode : public Client::Mode
{
public:
    MenuMode(Client& client, const memoryview<String>& choices, MenuCallback callback)
        : Client::Mode(client),
          m_callback(callback), m_choice_count(choices.size()), m_selected(0)
    {
        client.menu_show(choices);
    }

    ~MenuMode()
    {
        m_client.menu_hide();
    }

    void on_key(const Key& key, Context& context) override
    {
        if (key == Key(Key::Modifiers::Control, 'n') or
            key == Key(Key::Modifiers::Control, 'i') or
            key == Key(Key::Modifiers::None, 'j'))
        {
            if (++m_selected >= m_choice_count)
                m_selected = 0;
            m_client.menu_select(m_selected);
        }
        if (key == Key(Key::Modifiers::Control, 'p') or
            key == Key(Key::Modifiers::None, 'k'))
        {
            if (--m_selected < 0)
                m_selected = m_choice_count-1;
            m_client.menu_select(m_selected);
        }
        if (key == Key(Key::Modifiers::Control, 'm'))
        {
            // save callback as reset_normal_mode will delete this
            MenuCallback callback = std::move(m_callback);
            int selected = m_selected;
            m_client.reset_normal_mode();
            callback(selected, context);
        }
        if (key == Key(Key::Modifiers::None, 27))
        {
            m_client.reset_normal_mode();
        }
        if (key.modifiers == Key::Modifiers::None and
            key.key >= '0' and key.key <= '9')
        {
            m_client.menu_hide();
            // save callback as reset_normal_mode will delete this
            MenuCallback callback = std::move(m_callback);
            m_client.reset_normal_mode();
            callback(key.key - '0' - 1, context);
        }
   }

private:
    MenuCallback m_callback;
    int          m_selected;
    int          m_choice_count;
};

class Client::PromptMode : public Client::Mode
{
public:
    PromptMode(Client& client, const String& prompt, Completer completer, PromptCallback callback)
        : Client::Mode(client),
          m_prompt(prompt), m_completer(completer), m_callback(callback), m_cursor_pos(0)
    {
        m_history_it = ms_history[m_prompt].end();
        m_client.print_status(m_prompt, m_prompt.length());
    }

    ~PromptMode()
    {
        m_client.menu_hide();
    }

    void on_key(const Key& key, Context& context) override
    {
        std::vector<String>& history = ms_history[m_prompt];
        if (key == Key(Key::Modifiers::Control, 'm')) // enter
        {
            std::vector<String>::iterator it;
            while ((it = find(history, m_result)) != history.end())
                history.erase(it);

            history.push_back(m_result);
            m_client.print_status("");
            // save callback as reset_normal_mode will delete this
            PromptCallback callback = std::move(m_callback);
            String result = std::move(m_result);
            m_client.reset_normal_mode();
            callback(result, context);
            return;
        }
        else if (key == Key(Key::Modifiers::None, 27))
        {
            m_client.print_status("");
            m_client.reset_normal_mode();
            return;
        }
        else if (key == Key(Key::Modifiers::Control, 'p') or // previous
                 key == Key(Key::Modifiers::Control, 'c'))
        {
            if (m_history_it != history.begin())
            {
                if (m_history_it == history.end())
                   m_saved_result = m_result;
                auto it = m_history_it;
                // search for the previous history entry matching typed prefix
                CharCount prefix_length = m_saved_result.length();
                do
                {
                    --it;
                    if (it->substr(0, prefix_length) == m_saved_result)
                    {
                        m_history_it = it;
                        m_result     = *it;
                        m_cursor_pos = m_result.length();
                        break;
                    }
                } while (it != history.begin());
            }
        }
        else if (key == Key(Key::Modifiers::Control, 'n') or // next
                 key == Key(Key::Modifiers::Control, 'b'))
        {
            if (m_history_it != history.end())
            {
                CharCount prefix_length = m_saved_result.length();
                // search for the next history entry matching typed prefix
                ++m_history_it;
                while (m_history_it != history.end() and
                       m_history_it->substr(0, prefix_length) != m_saved_result)
                    ++m_history_it;

                if (m_history_it != history.end())
                    m_result = *m_history_it;
                else
                    m_result = m_saved_result;
                m_cursor_pos = m_result.length();
            }
        }
        else if (key == Key(Key::Modifiers::Control, 'd'))
        {
            if (m_cursor_pos > 0)
                --m_cursor_pos;
        }
        else if (key == Key(Key::Modifiers::Control, 'e'))
        {
            if (m_cursor_pos < m_result.length())
                ++m_cursor_pos;
        }
        else if (key == Key(Key::Modifiers::Control, 'g')) // backspace
        {
            if (m_cursor_pos != 0)
            {
                m_result = m_result.substr(0, m_cursor_pos - 1)
                       + m_result.substr(m_cursor_pos, String::npos);

                --m_cursor_pos;
            }

            m_client.menu_hide();
            m_current_completion = -1;
        }
        else if (key == Key(Key::Modifiers::Control, 'r'))
        {
            Key k = m_client.get_key();
            String reg = RegisterManager::instance()[k.key].values(context)[0];
            m_client.menu_hide();
            m_current_completion = -1;
            m_result = m_result.substr(0, m_cursor_pos) + reg + m_result.substr(m_cursor_pos, String::npos);
            m_cursor_pos += reg.length();
        }
        else if (key == Key(Key::Modifiers::Control, 'i')) // tab
        {
            if (m_current_completion == -1)
            {
                m_completions = m_completer(context, m_result, m_cursor_pos);
                if (m_completions.candidates.empty())
                    return;

                m_client.menu_hide();
                m_client.menu_show(m_completions.candidates);
                m_text_before_completion = m_result.substr(m_completions.start,
                                                         m_completions.end - m_completions.start);
            }
            ++m_current_completion;

            String completion;
            if (m_current_completion >= m_completions.candidates.size())
            {
                if (m_current_completion == m_completions.candidates.size() and
                    std::find(m_completions.candidates.begin(), m_completions.candidates.end(), m_text_before_completion) == m_completions.candidates.end())
                {
                    completion = m_text_before_completion;
                }
                else
                {
                    m_current_completion = 0;
                    completion = m_completions.candidates[0];
                }
            }
            else
                completion = m_completions.candidates[m_current_completion];

            m_client.menu_select(m_current_completion);
            m_result = m_result.substr(0, m_completions.start) + completion;
            m_cursor_pos = m_completions.start + completion.length();
        }
        else
        {
            m_client.menu_hide();
            m_current_completion = -1;
            m_result = m_result.substr(0, m_cursor_pos) + key.key + m_result.substr(m_cursor_pos, String::npos);
            ++m_cursor_pos;
        }
        m_client.print_status(m_prompt + m_result, m_prompt.length() + m_cursor_pos);
    }

private:
    PromptCallback m_callback;
    Completer      m_completer;
    const String   m_prompt;
    CharCount      m_cursor_pos;
    Completions    m_completions;
    int            m_current_completion = -1;
    String         m_text_before_completion;
    String         m_result;
    String         m_saved_result;

    static std::unordered_map<String, std::vector<String>> ms_history;
    std::vector<String>::iterator m_history_it;
};
std::unordered_map<String, std::vector<String>> Client::PromptMode::ms_history;

class Client::NextKeyMode : public Client::Mode
{
public:
    NextKeyMode(Client& client, KeyCallback callback)
        : Client::Mode(client), m_callback(callback) {}

    void on_key(const Key& key, Context& context) override
    {
        // save callback as reset_normal_mode will delete this
        KeyCallback callback = std::move(m_callback);
        m_client.reset_normal_mode();
        callback(key, context);
   }

private:
    KeyCallback m_callback;
};

class Client::InsertMode : public Client::Mode
{
public:
    InsertMode(Client& client, Editor& editor, IncrementalInserter::Mode mode)
        : Client::Mode(client), m_inserter(editor, mode)
    {
        m_client.m_last_insert.first = mode;
        m_client.m_last_insert.second.clear();
    }

    void on_key(const Key& key, Context& context) override
    {
        m_client.m_last_insert.second.push_back(key);
        if (m_insert_reg)
        {
            if (key.modifiers == Key::Modifiers::None)
                m_inserter.insert(RegisterManager::instance()[key.key].values(context));
            m_insert_reg = false;
            return;
        }
        switch (key.modifiers)
        {
        case Key::Modifiers::None:
            switch (key.key)
            {
            case 27:
                m_client.reset_normal_mode();
                return;
            default:
                m_inserter.insert(String() + key.key);
            }
            break;
        case Key::Modifiers::Control:
            switch (key.key)
            {
            case 'r':
                m_insert_reg = true;
                break;
            case 'm':
                m_inserter.insert(String() + '\n');
                break;
            case 'i':
                m_inserter.insert(String() + '\t');
                break;
            case 'd':
                m_inserter.move_cursors({0, -1});
                break;
            case 'e':
                m_inserter.move_cursors({0,  1});
                break;
            case 'g':
                m_inserter.erase();
                break;
            }
            break;
        }
    }
private:
    bool m_insert_reg = false;
    IncrementalInserter m_inserter;
};

Client::Client()
    : m_mode(new NormalMode(*this)),
      m_last_insert(IncrementalInserter::Mode::Insert, {})
{
}

void Client::insert(Editor& editor, IncrementalInserter::Mode mode)
{
    m_mode.reset(new InsertMode(*this, editor, mode));
}

void Client::repeat_last_insert(Editor& editor, Context& context)
{
    std::vector<Key> keys;
    swap(keys, m_last_insert.second);
    // m_last_insert will be refilled by the new InsertMode
    // this is very inefficient.
    m_mode.reset(new InsertMode(*this, editor, m_last_insert.first));
    for (auto& key : keys)
        m_mode->on_key(key, context);
    assert(dynamic_cast<NormalMode*>(m_mode.get()) != nullptr);
}

void Client::prompt(const String& prompt, Completer completer,
                    PromptCallback callback)
{
    m_mode.reset(new PromptMode(*this, prompt, completer, callback));
}

void Client::menu(const memoryview<String>& choices,
                  MenuCallback callback)
{
    m_mode.reset(new MenuMode(*this, choices, callback));
}

void Client::on_next_key(KeyCallback callback)
{
    m_mode.reset(new NextKeyMode(*this, callback));
}

void Client::handle_next_input(Context& context)
{
    m_mode->on_key(get_key(), context);
    context.draw_ifn();
}

void Client::reset_normal_mode()
{
    m_mode.reset(new NormalMode(*this));
}

}
<commit_msg>fix Client::repeat_last_insert when no last insert<commit_after>#include "client.hh"

#include "context.hh"
#include "register_manager.hh"

#include <unordered_map>

namespace Kakoune
{

extern std::unordered_map<Key, std::function<void (Context& context)>> keymap;

class Client::NormalMode : public Client::Mode
{
public:
    NormalMode(Client& client)
        : Client::Mode(client)
    {
    }

    void on_key(const Key& key, Context& context) override
    {
        if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
            m_count = m_count * 10 + key.key - '0';
        else
        {
            auto it = keymap.find(key);
            if (it != keymap.end())
            {
                context.numeric_param(m_count);
                // it's important to do that before calling the command,
                // as we may die during the command execution.
                m_count = 0;
                it->second(context);
            }
            else
                m_count = 0;
        }
    }

private:
    int m_count = 0;
};

class Client::MenuMode : public Client::Mode
{
public:
    MenuMode(Client& client, const memoryview<String>& choices, MenuCallback callback)
        : Client::Mode(client),
          m_callback(callback), m_choice_count(choices.size()), m_selected(0)
    {
        client.menu_show(choices);
    }

    ~MenuMode()
    {
        m_client.menu_hide();
    }

    void on_key(const Key& key, Context& context) override
    {
        if (key == Key(Key::Modifiers::Control, 'n') or
            key == Key(Key::Modifiers::Control, 'i') or
            key == Key(Key::Modifiers::None, 'j'))
        {
            if (++m_selected >= m_choice_count)
                m_selected = 0;
            m_client.menu_select(m_selected);
        }
        if (key == Key(Key::Modifiers::Control, 'p') or
            key == Key(Key::Modifiers::None, 'k'))
        {
            if (--m_selected < 0)
                m_selected = m_choice_count-1;
            m_client.menu_select(m_selected);
        }
        if (key == Key(Key::Modifiers::Control, 'm'))
        {
            // save callback as reset_normal_mode will delete this
            MenuCallback callback = std::move(m_callback);
            int selected = m_selected;
            m_client.reset_normal_mode();
            callback(selected, context);
        }
        if (key == Key(Key::Modifiers::None, 27))
        {
            m_client.reset_normal_mode();
        }
        if (key.modifiers == Key::Modifiers::None and
            key.key >= '0' and key.key <= '9')
        {
            m_client.menu_hide();
            // save callback as reset_normal_mode will delete this
            MenuCallback callback = std::move(m_callback);
            m_client.reset_normal_mode();
            callback(key.key - '0' - 1, context);
        }
   }

private:
    MenuCallback m_callback;
    int          m_selected;
    int          m_choice_count;
};

class Client::PromptMode : public Client::Mode
{
public:
    PromptMode(Client& client, const String& prompt, Completer completer, PromptCallback callback)
        : Client::Mode(client),
          m_prompt(prompt), m_completer(completer), m_callback(callback), m_cursor_pos(0)
    {
        m_history_it = ms_history[m_prompt].end();
        m_client.print_status(m_prompt, m_prompt.length());
    }

    ~PromptMode()
    {
        m_client.menu_hide();
    }

    void on_key(const Key& key, Context& context) override
    {
        std::vector<String>& history = ms_history[m_prompt];
        if (key == Key(Key::Modifiers::Control, 'm')) // enter
        {
            std::vector<String>::iterator it;
            while ((it = find(history, m_result)) != history.end())
                history.erase(it);

            history.push_back(m_result);
            m_client.print_status("");
            // save callback as reset_normal_mode will delete this
            PromptCallback callback = std::move(m_callback);
            String result = std::move(m_result);
            m_client.reset_normal_mode();
            callback(result, context);
            return;
        }
        else if (key == Key(Key::Modifiers::None, 27))
        {
            m_client.print_status("");
            m_client.reset_normal_mode();
            return;
        }
        else if (key == Key(Key::Modifiers::Control, 'p') or // previous
                 key == Key(Key::Modifiers::Control, 'c'))
        {
            if (m_history_it != history.begin())
            {
                if (m_history_it == history.end())
                   m_saved_result = m_result;
                auto it = m_history_it;
                // search for the previous history entry matching typed prefix
                CharCount prefix_length = m_saved_result.length();
                do
                {
                    --it;
                    if (it->substr(0, prefix_length) == m_saved_result)
                    {
                        m_history_it = it;
                        m_result     = *it;
                        m_cursor_pos = m_result.length();
                        break;
                    }
                } while (it != history.begin());
            }
        }
        else if (key == Key(Key::Modifiers::Control, 'n') or // next
                 key == Key(Key::Modifiers::Control, 'b'))
        {
            if (m_history_it != history.end())
            {
                CharCount prefix_length = m_saved_result.length();
                // search for the next history entry matching typed prefix
                ++m_history_it;
                while (m_history_it != history.end() and
                       m_history_it->substr(0, prefix_length) != m_saved_result)
                    ++m_history_it;

                if (m_history_it != history.end())
                    m_result = *m_history_it;
                else
                    m_result = m_saved_result;
                m_cursor_pos = m_result.length();
            }
        }
        else if (key == Key(Key::Modifiers::Control, 'd'))
        {
            if (m_cursor_pos > 0)
                --m_cursor_pos;
        }
        else if (key == Key(Key::Modifiers::Control, 'e'))
        {
            if (m_cursor_pos < m_result.length())
                ++m_cursor_pos;
        }
        else if (key == Key(Key::Modifiers::Control, 'g')) // backspace
        {
            if (m_cursor_pos != 0)
            {
                m_result = m_result.substr(0, m_cursor_pos - 1)
                       + m_result.substr(m_cursor_pos, String::npos);

                --m_cursor_pos;
            }

            m_client.menu_hide();
            m_current_completion = -1;
        }
        else if (key == Key(Key::Modifiers::Control, 'r'))
        {
            Key k = m_client.get_key();
            String reg = RegisterManager::instance()[k.key].values(context)[0];
            m_client.menu_hide();
            m_current_completion = -1;
            m_result = m_result.substr(0, m_cursor_pos) + reg + m_result.substr(m_cursor_pos, String::npos);
            m_cursor_pos += reg.length();
        }
        else if (key == Key(Key::Modifiers::Control, 'i')) // tab
        {
            if (m_current_completion == -1)
            {
                m_completions = m_completer(context, m_result, m_cursor_pos);
                if (m_completions.candidates.empty())
                    return;

                m_client.menu_hide();
                m_client.menu_show(m_completions.candidates);
                m_text_before_completion = m_result.substr(m_completions.start,
                                                         m_completions.end - m_completions.start);
            }
            ++m_current_completion;

            String completion;
            if (m_current_completion >= m_completions.candidates.size())
            {
                if (m_current_completion == m_completions.candidates.size() and
                    std::find(m_completions.candidates.begin(), m_completions.candidates.end(), m_text_before_completion) == m_completions.candidates.end())
                {
                    completion = m_text_before_completion;
                }
                else
                {
                    m_current_completion = 0;
                    completion = m_completions.candidates[0];
                }
            }
            else
                completion = m_completions.candidates[m_current_completion];

            m_client.menu_select(m_current_completion);
            m_result = m_result.substr(0, m_completions.start) + completion;
            m_cursor_pos = m_completions.start + completion.length();
        }
        else
        {
            m_client.menu_hide();
            m_current_completion = -1;
            m_result = m_result.substr(0, m_cursor_pos) + key.key + m_result.substr(m_cursor_pos, String::npos);
            ++m_cursor_pos;
        }
        m_client.print_status(m_prompt + m_result, m_prompt.length() + m_cursor_pos);
    }

private:
    PromptCallback m_callback;
    Completer      m_completer;
    const String   m_prompt;
    CharCount      m_cursor_pos;
    Completions    m_completions;
    int            m_current_completion = -1;
    String         m_text_before_completion;
    String         m_result;
    String         m_saved_result;

    static std::unordered_map<String, std::vector<String>> ms_history;
    std::vector<String>::iterator m_history_it;
};
std::unordered_map<String, std::vector<String>> Client::PromptMode::ms_history;

class Client::NextKeyMode : public Client::Mode
{
public:
    NextKeyMode(Client& client, KeyCallback callback)
        : Client::Mode(client), m_callback(callback) {}

    void on_key(const Key& key, Context& context) override
    {
        // save callback as reset_normal_mode will delete this
        KeyCallback callback = std::move(m_callback);
        m_client.reset_normal_mode();
        callback(key, context);
   }

private:
    KeyCallback m_callback;
};

class Client::InsertMode : public Client::Mode
{
public:
    InsertMode(Client& client, Editor& editor, IncrementalInserter::Mode mode)
        : Client::Mode(client), m_inserter(editor, mode)
    {
        m_client.m_last_insert.first = mode;
        m_client.m_last_insert.second.clear();
    }

    void on_key(const Key& key, Context& context) override
    {
        m_client.m_last_insert.second.push_back(key);
        if (m_insert_reg)
        {
            if (key.modifiers == Key::Modifiers::None)
                m_inserter.insert(RegisterManager::instance()[key.key].values(context));
            m_insert_reg = false;
            return;
        }
        switch (key.modifiers)
        {
        case Key::Modifiers::None:
            switch (key.key)
            {
            case 27:
                m_client.reset_normal_mode();
                return;
            default:
                m_inserter.insert(String() + key.key);
            }
            break;
        case Key::Modifiers::Control:
            switch (key.key)
            {
            case 'r':
                m_insert_reg = true;
                break;
            case 'm':
                m_inserter.insert(String() + '\n');
                break;
            case 'i':
                m_inserter.insert(String() + '\t');
                break;
            case 'd':
                m_inserter.move_cursors({0, -1});
                break;
            case 'e':
                m_inserter.move_cursors({0,  1});
                break;
            case 'g':
                m_inserter.erase();
                break;
            }
            break;
        }
    }
private:
    bool m_insert_reg = false;
    IncrementalInserter m_inserter;
};

Client::Client()
    : m_mode(new NormalMode(*this)),
      m_last_insert(IncrementalInserter::Mode::Insert, {})
{
}

void Client::insert(Editor& editor, IncrementalInserter::Mode mode)
{
    m_mode.reset(new InsertMode(*this, editor, mode));
}

void Client::repeat_last_insert(Editor& editor, Context& context)
{
    if (m_last_insert.second.empty())
        return;

    std::vector<Key> keys;
    swap(keys, m_last_insert.second);
    // m_last_insert will be refilled by the new InsertMode
    // this is very inefficient.
    m_mode.reset(new InsertMode(*this, editor, m_last_insert.first));
    for (auto& key : keys)
        m_mode->on_key(key, context);
    assert(dynamic_cast<NormalMode*>(m_mode.get()) != nullptr);
}

void Client::prompt(const String& prompt, Completer completer,
                    PromptCallback callback)
{
    m_mode.reset(new PromptMode(*this, prompt, completer, callback));
}

void Client::menu(const memoryview<String>& choices,
                  MenuCallback callback)
{
    m_mode.reset(new MenuMode(*this, choices, callback));
}

void Client::on_next_key(KeyCallback callback)
{
    m_mode.reset(new NextKeyMode(*this, callback));
}

void Client::handle_next_input(Context& context)
{
    m_mode->on_key(get_key(), context);
    context.draw_ifn();
}

void Client::reset_normal_mode()
{
    m_mode.reset(new NormalMode(*this));
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2015 The Bitcoin Core developers
// Copyright (c) 2015-2017 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "coins.h"

#include "consensus/consensus.h"
#include "memusage.h"
#include "random.h"
#include "util.h"

#include <assert.h>

bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, size_t &nChildCachedCoinsUsage) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }

CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, size_t &nChildCachedCoinsUsage) { return base->BatchWrite(mapCoins, hashBlock, nChildCachedCoinsUsage); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }

SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}

CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}

size_t CCoinsViewCache::DynamicMemoryUsage() const {
    LOCK(cs_utxo);
    return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
}

size_t CCoinsViewCache::ResetCachedCoinUsage() const
{

    LOCK(cs_utxo);
    size_t newCachedCoinsUsage = 0;
    for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++)
        newCachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
    if (cachedCoinsUsage != newCachedCoinsUsage)
    {
        error("Resetting: cachedCoinsUsage has drifted - before %lld after %lld", cachedCoinsUsage,
            newCachedCoinsUsage);
        cachedCoinsUsage = newCachedCoinsUsage;
    }
    return newCachedCoinsUsage;
}

CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
    // requires cs_utxo
    CCoinsMap::iterator it = cacheCoins.find(outpoint);
    if (it != cacheCoins.end())
        return it;
    Coin tmp;
    if (!base->GetCoin(outpoint, tmp))
        return cacheCoins.end();
    CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
    if (ret->second.coin.IsSpent()) {
        // The parent only has an empty entry for this outpoint; we can consider our
        // version as fresh.
        ret->second.flags = CCoinsCacheEntry::FRESH;
    }
    cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage();
    return ret;
}

bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it != cacheCoins.end()) {
        coin = it->second.coin;
        return true;
    }
    return false;
}

void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
    assert(!coin.IsSpent());
    if (coin.out.scriptPubKey.IsUnspendable()) return;
    CCoinsMap::iterator it;
    bool inserted;
    std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
    bool fresh = false;
    if (!inserted) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    }
    if (!possible_overwrite) {
        if (!it->second.coin.IsSpent()) {
            throw std::logic_error("Adding new coin that replaces non-pruned entry");
        }
        fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
    }
    it->second.coin = std::move(coin);
    it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
    cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}

void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
    bool fCoinbase = tx.IsCoinBase();
    const uint256& txid = tx.GetHash();
    for (size_t i = 0; i < tx.vout.size(); ++i) {
        // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
        // deal with the pre-BIP30 occurrances of duplicate coinbase transactions.
        cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), fCoinbase);
    }
}

void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
    CCoinsMap::iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) return;
    cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    if (moveout) {
        *moveout = std::move(it->second.coin);
    }
    if (it->second.flags & CCoinsCacheEntry::FRESH) {
        cacheCoins.erase(it);
    } else {
        it->second.flags |= CCoinsCacheEntry::DIRTY;
        it->second.coin.Clear();
    }
}

static const Coin coinEmpty;

const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) {
        return coinEmpty;
    } else {
        return it->second.coin;
    }
}

bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}

bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
    return it != cacheCoins.end();
}

uint256 CCoinsViewCache::GetBestBlock() const {
    LOCK(cs_utxo);
    if (hashBlock.IsNull())
        hashBlock = base->GetBestBlock();
    return hashBlock;
}

void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
    LOCK(cs_utxo);
    hashBlock = hashBlockIn;
}

bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn, size_t &nChildCachedCoinsUsage) {
    LOCK(cs_utxo);
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {

        if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
            // Update usage of the chile cache before we do any swapping and deleting
            nChildCachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();

            CCoinsMap::iterator itUs = cacheCoins.find(it->first);
            if (itUs == cacheCoins.end()) {
                // The parent cache does not have an entry, while the child does
                // We can ignore it if it's both FRESH and pruned in the child
                if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
                    // Otherwise we will need to create it in the parent
                    // and move the data up and mark it as dirty
                    CCoinsCacheEntry& entry = cacheCoins[it->first];
                    entry.coin = std::move(it->second.coin);
                    cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
                    entry.flags = CCoinsCacheEntry::DIRTY;
                    // We can mark it FRESH in the parent if it was FRESH in the child
                    // Otherwise it might have just been flushed from the parent's cache
                    // and already exist in the grandparent
                    if (it->second.flags & CCoinsCacheEntry::FRESH)
                        entry.flags |= CCoinsCacheEntry::FRESH;
                }
            } else {
                // Assert that the child cache entry was not marked FRESH if the
                // parent cache entry has unspent outputs. If this ever happens,
                // it means the FRESH flag was misapplied and there is a logic
                // error in the calling code.
                if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
                    throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");

                // Found the entry in the parent cache
                if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
                    // The grandparent does not have an entry, and the child is
                    // modified and being pruned. This means we can just delete
                    // it from the parent.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    cacheCoins.erase(itUs);
                } else {
                    // A normal modification.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.coin = std::move(it->second.coin);
                    cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.flags |= CCoinsCacheEntry::DIRTY;
                }
            }

            CCoinsMap::iterator itOld = it++;
            mapCoins.erase(itOld);
        }
        else
            it++;
    }
    hashBlock = hashBlockIn;
    return true;
}

bool CCoinsViewCache::Flush() {
    LOCK(cs_utxo);
    bool fOk = base->BatchWrite(cacheCoins, hashBlock, cachedCoinsUsage);
    return fOk;
}

void CCoinsViewCache::Trim(size_t nTrimSize) const
{
    uint64_t nTrimmed = 0;

    LOCK(cs_utxo);
    CCoinsMap::iterator iter = cacheCoins.begin();
    while (DynamicMemoryUsage() > nTrimSize)
    {
        if (iter == cacheCoins.end())
            break;

        // Only erase entries that have not been modified
        if (iter->second.flags == 0)
        {
            cachedCoinsUsage -= iter->second.coin.DynamicMemoryUsage();

            CCoinsMap::iterator itOld = iter++;
            cacheCoins.erase(itOld);
            nTrimmed++;
        }
        else
            iter++;
    }

    if (nTrimmed > 0)
        LogPrint("coindb", "Trimmed %ld from the CoinsViewCache, current size after trim: %ld and usage %ld bytes\n", nTrimmed, cacheCoins.size(), cachedCoinsUsage);
}

void CCoinsViewCache::Uncache(const COutPoint& hash)
{
    LOCK(cs_utxo);
    CCoinsMap::iterator it = cacheCoins.find(hash);
    if (it != cacheCoins.end() && it->second.flags == 0) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
        cacheCoins.erase(it);
    }
}

unsigned int CCoinsViewCache::GetCacheSize() const {
    LOCK(cs_utxo);
    return cacheCoins.size();
}

CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
{
    LOCK(cs_utxo);
    if (tx.IsCoinBase())
        return 0;

    CAmount nResult = 0;
    for (unsigned int i = 0; i < tx.vin.size(); i++)
        nResult += AccessCoin(tx.vin[i].prevout).out.nValue;

    return nResult;
}

bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
    LOCK(cs_utxo);
    if (!tx.IsCoinBase()) {
        for (unsigned int i = 0; i < tx.vin.size(); i++) {
            if (!HaveCoin(tx.vin[i].prevout)) {
                return false;
            }
        }
    }
    return true;
}

double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
{
    LOCK(cs_utxo);
    inChainInputValue = 0;
    if (tx.IsCoinBase())
        return 0.0;
    double dResult = 0.0;
    BOOST_FOREACH(const CTxIn& txin, tx.vin)
    {
        const Coin &coin = AccessCoin(txin.prevout);
        if (coin.IsSpent()) continue;
        if (coin.nHeight <= nHeight) {
            dResult += coin.out.nValue * (nHeight-coin.nHeight);
            inChainInputValue += coin.out.nValue;
        }
    }
    return tx.ComputePriority(dResult);
}

CCoinsViewCursor::~CCoinsViewCursor()
{
}

static const size_t MAX_OUTPUTS_PER_BLOCK = 1000000 /  ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO:
const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
{
    COutPoint iter(txid, 0);
    while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
        const Coin& alternate = view.AccessCoin(iter);
        if (!alternate.IsSpent()) return alternate;
        ++iter.n;
    }
    return coinEmpty;
}

<commit_msg>In AccessByTxid use DEFAULT_LARGEST_TRANSACTION<commit_after>// Copyright (c) 2012-2015 The Bitcoin Core developers
// Copyright (c) 2015-2017 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "coins.h"

#include "consensus/consensus.h"
#include "memusage.h"
#include "random.h"
#include "util.h"

#include <assert.h>

bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, size_t &nChildCachedCoinsUsage) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }

CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, size_t &nChildCachedCoinsUsage) { return base->BatchWrite(mapCoins, hashBlock, nChildCachedCoinsUsage); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }

SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}

CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}

size_t CCoinsViewCache::DynamicMemoryUsage() const {
    LOCK(cs_utxo);
    return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
}

size_t CCoinsViewCache::ResetCachedCoinUsage() const
{

    LOCK(cs_utxo);
    size_t newCachedCoinsUsage = 0;
    for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++)
        newCachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
    if (cachedCoinsUsage != newCachedCoinsUsage)
    {
        error("Resetting: cachedCoinsUsage has drifted - before %lld after %lld", cachedCoinsUsage,
            newCachedCoinsUsage);
        cachedCoinsUsage = newCachedCoinsUsage;
    }
    return newCachedCoinsUsage;
}

CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
    // requires cs_utxo
    CCoinsMap::iterator it = cacheCoins.find(outpoint);
    if (it != cacheCoins.end())
        return it;
    Coin tmp;
    if (!base->GetCoin(outpoint, tmp))
        return cacheCoins.end();
    CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
    if (ret->second.coin.IsSpent()) {
        // The parent only has an empty entry for this outpoint; we can consider our
        // version as fresh.
        ret->second.flags = CCoinsCacheEntry::FRESH;
    }
    cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage();
    return ret;
}

bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it != cacheCoins.end()) {
        coin = it->second.coin;
        return true;
    }
    return false;
}

void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
    assert(!coin.IsSpent());
    if (coin.out.scriptPubKey.IsUnspendable()) return;
    CCoinsMap::iterator it;
    bool inserted;
    std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
    bool fresh = false;
    if (!inserted) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    }
    if (!possible_overwrite) {
        if (!it->second.coin.IsSpent()) {
            throw std::logic_error("Adding new coin that replaces non-pruned entry");
        }
        fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
    }
    it->second.coin = std::move(coin);
    it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
    cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}

void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
    bool fCoinbase = tx.IsCoinBase();
    const uint256& txid = tx.GetHash();
    for (size_t i = 0; i < tx.vout.size(); ++i) {
        // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
        // deal with the pre-BIP30 occurrances of duplicate coinbase transactions.
        cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), fCoinbase);
    }
}

void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
    CCoinsMap::iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) return;
    cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    if (moveout) {
        *moveout = std::move(it->second.coin);
    }
    if (it->second.flags & CCoinsCacheEntry::FRESH) {
        cacheCoins.erase(it);
    } else {
        it->second.flags |= CCoinsCacheEntry::DIRTY;
        it->second.coin.Clear();
    }
}

static const Coin coinEmpty;

const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) {
        return coinEmpty;
    } else {
        return it->second.coin;
    }
}

bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}

bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
    return it != cacheCoins.end();
}

uint256 CCoinsViewCache::GetBestBlock() const {
    LOCK(cs_utxo);
    if (hashBlock.IsNull())
        hashBlock = base->GetBestBlock();
    return hashBlock;
}

void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
    LOCK(cs_utxo);
    hashBlock = hashBlockIn;
}

bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn, size_t &nChildCachedCoinsUsage) {
    LOCK(cs_utxo);
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {

        if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
            // Update usage of the chile cache before we do any swapping and deleting
            nChildCachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();

            CCoinsMap::iterator itUs = cacheCoins.find(it->first);
            if (itUs == cacheCoins.end()) {
                // The parent cache does not have an entry, while the child does
                // We can ignore it if it's both FRESH and pruned in the child
                if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
                    // Otherwise we will need to create it in the parent
                    // and move the data up and mark it as dirty
                    CCoinsCacheEntry& entry = cacheCoins[it->first];
                    entry.coin = std::move(it->second.coin);
                    cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
                    entry.flags = CCoinsCacheEntry::DIRTY;
                    // We can mark it FRESH in the parent if it was FRESH in the child
                    // Otherwise it might have just been flushed from the parent's cache
                    // and already exist in the grandparent
                    if (it->second.flags & CCoinsCacheEntry::FRESH)
                        entry.flags |= CCoinsCacheEntry::FRESH;
                }
            } else {
                // Assert that the child cache entry was not marked FRESH if the
                // parent cache entry has unspent outputs. If this ever happens,
                // it means the FRESH flag was misapplied and there is a logic
                // error in the calling code.
                if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
                    throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");

                // Found the entry in the parent cache
                if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
                    // The grandparent does not have an entry, and the child is
                    // modified and being pruned. This means we can just delete
                    // it from the parent.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    cacheCoins.erase(itUs);
                } else {
                    // A normal modification.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.coin = std::move(it->second.coin);
                    cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.flags |= CCoinsCacheEntry::DIRTY;
                }
            }

            CCoinsMap::iterator itOld = it++;
            mapCoins.erase(itOld);
        }
        else
            it++;
    }
    hashBlock = hashBlockIn;
    return true;
}

bool CCoinsViewCache::Flush() {
    LOCK(cs_utxo);
    bool fOk = base->BatchWrite(cacheCoins, hashBlock, cachedCoinsUsage);
    return fOk;
}

void CCoinsViewCache::Trim(size_t nTrimSize) const
{
    uint64_t nTrimmed = 0;

    LOCK(cs_utxo);
    CCoinsMap::iterator iter = cacheCoins.begin();
    while (DynamicMemoryUsage() > nTrimSize)
    {
        if (iter == cacheCoins.end())
            break;

        // Only erase entries that have not been modified
        if (iter->second.flags == 0)
        {
            cachedCoinsUsage -= iter->second.coin.DynamicMemoryUsage();

            CCoinsMap::iterator itOld = iter++;
            cacheCoins.erase(itOld);
            nTrimmed++;
        }
        else
            iter++;
    }

    if (nTrimmed > 0)
        LogPrint("coindb", "Trimmed %ld from the CoinsViewCache, current size after trim: %ld and usage %ld bytes\n", nTrimmed, cacheCoins.size(), cachedCoinsUsage);
}

void CCoinsViewCache::Uncache(const COutPoint& hash)
{
    LOCK(cs_utxo);
    CCoinsMap::iterator it = cacheCoins.find(hash);
    if (it != cacheCoins.end() && it->second.flags == 0) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
        cacheCoins.erase(it);
    }
}

unsigned int CCoinsViewCache::GetCacheSize() const {
    LOCK(cs_utxo);
    return cacheCoins.size();
}

CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
{
    LOCK(cs_utxo);
    if (tx.IsCoinBase())
        return 0;

    CAmount nResult = 0;
    for (unsigned int i = 0; i < tx.vin.size(); i++)
        nResult += AccessCoin(tx.vin[i].prevout).out.nValue;

    return nResult;
}

bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
    LOCK(cs_utxo);
    if (!tx.IsCoinBase()) {
        for (unsigned int i = 0; i < tx.vin.size(); i++) {
            if (!HaveCoin(tx.vin[i].prevout)) {
                return false;
            }
        }
    }
    return true;
}

double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
{
    LOCK(cs_utxo);
    inChainInputValue = 0;
    if (tx.IsCoinBase())
        return 0.0;
    double dResult = 0.0;
    BOOST_FOREACH(const CTxIn& txin, tx.vin)
    {
        const Coin &coin = AccessCoin(txin.prevout);
        if (coin.IsSpent()) continue;
        if (coin.nHeight <= nHeight) {
            dResult += coin.out.nValue * (nHeight-coin.nHeight);
            inChainInputValue += coin.out.nValue;
        }
    }
    return tx.ComputePriority(dResult);
}

CCoinsViewCursor::~CCoinsViewCursor()
{
}

static const size_t nMaxOutputsPerBlock = DEFAULT_LARGEST_TRANSACTION / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION);
const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
{
    COutPoint iter(txid, 0);
    while (iter.n < nMaxOutputsPerBlock) {
        const Coin& alternate = view.AccessCoin(iter);
        if (!alternate.IsSpent()) return alternate;
        ++iter.n;
    }
    return coinEmpty;
}

<|endoftext|>


<commit_before>/**
Copyright (c) 2015, Nsynapse Inc.
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 <organization> 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 <COPYRIGHT HOLDER> 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.
 */

/**
 * @mainpage	COSSB(Component-based Open & Simple Service Broker)
 * @details
 */

/**
 * @file		cossb.cpp
 * @brief		COSS Broker application
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 6. 9
 * @details		COSSB Application
 */

#include <iostream>
#include <csignal>
#include <cstdlib>
#include <popt.h>
#include <memory>
#include <dirent.h>
#include <unistd.h>
#include <cossb.hpp>

using namespace std;
using namespace cossb;

void terminate() {
	core::destroy();
	exit(EXIT_SUCCESS);
}

/**
 * @brief	SIGINT signal callback function
 * @details	Stop all services and destroy all instances
 */
void sigc_interrupt(int param) {
	::terminate();
}

/**
 * @brief	Main routine
 * @param	command
 * @details	Start with default components
 */
int main(int argc, char* argv[])
{
	signal(SIGINT, sigc_interrupt);

	char* manifest_file = nullptr;
	struct poptOption optionTable[] =
	{
		{"run",			'r', POPT_ARG_STRING, (void*)manifest_file, 'r', "Run Broker with manifest file", "*.xml manifest file"},
		{"version",		'v', POPT_ARG_NONE, 0, 'v', "Show COSSB Version", "version"},
		POPT_AUTOHELP
		POPT_TABLEEND
	};
	poptContext optionCon = poptGetContext(NULL, argc, (const char**)argv, optionTable, 0);
	poptSetOtherOptionHelp(optionCon, "<option>");

	if(argc<2)
	{
		std::cout << poptStrerror(POPT_ERROR_NOARG) << endl;
		exit(EXIT_SUCCESS);
	}

	//only one opt
	int opt = poptGetNextOpt(optionCon);
	if(opt>=0)
	{
		switch(opt)
		{
		/* run with manifest file */
		case 'r': {
			cossb_log->log(log::loglevel::INFO, fmt::format("{}{} Now Starting....",COSSB_NAME, COSSB_VERSION).c_str());

			if(!core::init((const char*)poptGetOptArg(optionCon)))
				::terminate();

			core::start();
			pause();

		} break;

		/* show cossb version */
		case 'v':{ std::cout << COSSB_NAME << COSSB_VERSION << " (Built " << __DATE__ << " " <<__TIME__ << ")" << std::endl;	exit(EXIT_SUCCESS); } break;
		}
	}

	if (opt<-1)
	{
		cout << poptBadOption(optionCon, POPT_BADOPTION_NOALIAS) << ":" << poptStrerror(opt) << endl;
		::terminate();
	}

	poptFreeContext(optionCon);

	::terminate();

	return 0;
}
<commit_msg>fixed(not a bug) code for ambiguity (same namespace with boost::core)<commit_after>/**
Copyright (c) 2015, Nsynapse Inc.
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 <organization> 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 <COPYRIGHT HOLDER> 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.
 */

/**
 * @mainpage	COSSB(Component-based Open & Simple Service Broker)
 * @details
 */

/**
 * @file		cossb.cpp
 * @brief		COSS Broker application
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 6. 9
 * @details		COSSB Application
 */

#include <iostream>
#include <csignal>
#include <cstdlib>
#include <popt.h>
#include <memory>
#include <dirent.h>
#include <unistd.h>
#include <cossb.hpp>

using namespace std;

void terminate() {
	cossb::core::destroy();
	exit(EXIT_SUCCESS);
}

/**
 * @brief	SIGINT signal callback function
 * @details	Stop all services and destroy all instances
 */
void sigc_interrupt(int param) {
	::terminate();
}

/**
 * @brief	Main routine
 * @param	command
 * @details	Start with default components
 */
int main(int argc, char* argv[])
{
	signal(SIGINT, sigc_interrupt);

	char* manifest_file = nullptr;
	struct poptOption optionTable[] =
	{
		{"run",			'r', POPT_ARG_STRING, (void*)manifest_file, 'r', "Run Broker with manifest file", "*.xml manifest file"},
		{"version",		'v', POPT_ARG_NONE, 0, 'v', "Show COSSB Version", "version"},
		POPT_AUTOHELP
		POPT_TABLEEND
	};
	poptContext optionCon = poptGetContext(NULL, argc, (const char**)argv, optionTable, 0);
	poptSetOtherOptionHelp(optionCon, "<option>");

	if(argc<2)
	{
		std::cout << poptStrerror(POPT_ERROR_NOARG) << endl;
		exit(EXIT_SUCCESS);
	}

	//only one opt
	int opt = poptGetNextOpt(optionCon);
	if(opt>=0)
	{
		switch(opt)
		{
		/* run with manifest file */
		case 'r': {
			cossb_log->log(log::loglevel::INFO, fmt::format("{}{} Now Starting....",COSSB_NAME, COSSB_VERSION).c_str());

			if(!cossb::core::init((const char*)poptGetOptArg(optionCon)))
				::terminate();

			cossb::core::start();
			pause();

		} break;

		/* show cossb version */
		case 'v':{ std::cout << COSSB_NAME << COSSB_VERSION << " (Built " << __DATE__ << " " <<__TIME__ << ")" << std::endl;	exit(EXIT_SUCCESS); } break;
		}
	}

	if (opt<-1)
	{
		cout << poptBadOption(optionCon, POPT_BADOPTION_NOALIAS) << ":" << poptStrerror(opt) << endl;
		::terminate();
	}

	poptFreeContext(optionCon);

	::terminate();

	return 0;
}
<|endoftext|>


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

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "LibCxx.h"

#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace {

    class ListEntry
    {
    private:
        static const std::initializer_list<size_t> __prev_idx;
        static const std::initializer_list<size_t> __next_idx;
    public:
        ListEntry() = default;
        ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
        ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
        ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}

        ListEntry
        next ()
        {
            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildAtIndexPath({0,1}));
        }

        ListEntry
        prev ()
        {
            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildAtIndexPath({0,0}));
        }

        uint64_t
        value () const
        {
            if (!m_entry_sp)
                return 0;
            return m_entry_sp->GetValueAsUnsigned(0);
        }

        bool
        null()
        {
            return (value() == 0);
        }

        explicit operator bool ()
        {
            return GetEntry().get() != nullptr && null() == false;
        }

        ValueObjectSP
        GetEntry ()
        {
            return m_entry_sp;
        }

        void
        SetEntry (ValueObjectSP entry)
        {
            m_entry_sp = entry;
        }

        bool
        operator == (const ListEntry& rhs) const
        {
            return value() == rhs.value();
        }

        bool
        operator != (const ListEntry& rhs) const
        {
            return !(*this == rhs);
        }

    private:
        ValueObjectSP m_entry_sp;
    };

} // end anonymous namespace

namespace lldb_private {
    namespace formatters {
        class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
        {
        public:
            LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

            ~LibcxxStdListSyntheticFrontEnd() override = default;

            size_t
            CalculateNumChildren() override;

            lldb::ValueObjectSP
            GetChildAtIndex(size_t idx) override;

            bool
            Update() override;

            bool
            MightHaveChildren() override;

            size_t
            GetIndexOfChildWithName(const ConstString &name) override;

        private:
            bool
            HasLoop(size_t count);

            size_t m_list_capping_size;
            static const bool g_use_loop_detect = true;

            size_t m_loop_detected; // The number of elements that have had loop detection run over them.
            ListEntry m_slow_runner; // Used for loop detection
            ListEntry m_fast_runner; // Used for loop detection

            lldb::addr_t m_node_address;
            ValueObject* m_head;
            ValueObject* m_tail;
            CompilerType m_element_type;
            size_t m_count;
            std::map<size_t,lldb::ValueObjectSP> m_children;
        };
    } // namespace formatters
} // namespace lldb_private

class ListIterator
{
public:
    ListIterator() = default;
    ListIterator (ListEntry entry) : m_entry(entry) {}
    ListIterator (ValueObjectSP entry) : m_entry(entry) {}
    ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
    ListIterator (ValueObject* entry) : m_entry(entry) {}

    ValueObjectSP
    value ()
    {
        return m_entry.GetEntry();
    }

    ValueObjectSP
    advance (size_t count)
    {
        if (count == 0)
            return m_entry.GetEntry();
        if (count == 1)
        {
            next ();
            return m_entry.GetEntry();
        }
        while (count > 0)
        {
            next ();
            count--;
            if (m_entry.null())
                return lldb::ValueObjectSP();
        }
        return m_entry.GetEntry();
    }

    bool
    operator == (const ListIterator& rhs) const
    {
        return (rhs.m_entry == m_entry);
    }

protected:
    void
    next ()
    {
        m_entry = m_entry.next();
    }

    void
    prev ()
    {
        m_entry = m_entry.prev();
    }

private:
    ListEntry m_entry;
};

lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_list_capping_size(0),
m_loop_detected(0),
m_node_address(),
m_head(NULL),
m_tail(NULL),
m_element_type(),
m_count(UINT32_MAX),
m_children()
{
    if (valobj_sp)
        Update();
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count)
{
    if (g_use_loop_detect == false)
        return false;
    // don't bother checking for a loop if we won't actually need to jump nodes
    if (m_count < 2)
        return false;

    if (m_loop_detected == 0)
    {
        // This is the first time we are being run (after the last update). Set up the loop
        // invariant for the first element.
        m_slow_runner = ListEntry(m_head).next();
        m_fast_runner = m_slow_runner.next();
        m_loop_detected = 1;
    }

    // Loop invariant:
    // Loop detection has been run over the first m_loop_detected elements. If m_slow_runner ==
    // m_fast_runner then the loop has been detected after m_loop_detected elements.
    const size_t steps_to_run = std::min(count,m_count);
    while (m_loop_detected < steps_to_run
            && m_slow_runner
            && m_fast_runner
            && m_slow_runner != m_fast_runner) {

        m_slow_runner = m_slow_runner.next();
        m_fast_runner = m_fast_runner.next().next();
        m_loop_detected++;
    }
    if (count <= m_loop_detected)
        return false; // No loop in the first m_loop_detected elements.
    if (!m_slow_runner || !m_fast_runner)
        return false; // Reached the end of the list. Definitely no loops.
    return m_slow_runner == m_fast_runner;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
{
    if (m_count != UINT32_MAX)
        return m_count;
    if (!m_head || !m_tail || m_node_address == 0)
        return 0;
    ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
    if (size_alloc)
    {
        ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
        if (first)
        {
            m_count = first->GetValueAsUnsigned(UINT32_MAX);
        }
    }
    if (m_count != UINT32_MAX)
    {
        return m_count;
    }
    else
    {
        uint64_t next_val = m_head->GetValueAsUnsigned(0);
        uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
        if (next_val == 0 || prev_val == 0)
            return 0;
        if (next_val == m_node_address)
            return 0;
        if (next_val == prev_val)
            return 1;
        uint64_t size = 2;
        ListEntry current(m_head);
        while (current.next() && current.next().value() != m_node_address)
        {
            size++;
            current = current.next();
            if (size > m_list_capping_size)
                break;
        }
        return m_count = (size-1);
    }
}

lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
    if (idx >= CalculateNumChildren())
        return lldb::ValueObjectSP();

    if (!m_head || !m_tail || m_node_address == 0)
        return lldb::ValueObjectSP();

    auto cached = m_children.find(idx);
    if (cached != m_children.end())
        return cached->second;

    if (HasLoop(idx+1))
        return lldb::ValueObjectSP();

    ListIterator current(m_head);
    ValueObjectSP current_sp(current.advance(idx));
    if (!current_sp)
        return lldb::ValueObjectSP();
    current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
    if (!current_sp)
        return lldb::ValueObjectSP();
    // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
    DataExtractor data;
    Error error;
    current_sp->GetData(data, error);
    if (error.Fail())
        return lldb::ValueObjectSP();

    StreamString name;
    name.Printf("[%" PRIu64 "]", (uint64_t)idx);
    return (m_children[idx] = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
{
    m_children.clear();
    m_head = m_tail = NULL;
    m_node_address = 0;
    m_count = UINT32_MAX;
    m_loop_detected = 0;
    m_slow_runner.SetEntry(nullptr);
    m_fast_runner.SetEntry(nullptr);

    Error err;
    ValueObjectSP backend_addr(m_backend.AddressOf(err));
    m_list_capping_size = 0;
    if (m_backend.GetTargetSP())
        m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
    if (m_list_capping_size == 0)
        m_list_capping_size = 255;
    if (err.Fail() || backend_addr.get() == NULL)
        return false;
    m_node_address = backend_addr->GetValueAsUnsigned(0);
    if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
        return false;
    ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
    if (!impl_sp)
        return false;
    CompilerType list_type = m_backend.GetCompilerType();
    if (list_type.IsReferenceType())
        list_type = list_type.GetNonReferenceType();

    if (list_type.GetNumTemplateArguments() == 0)
        return false;
    lldb::TemplateArgumentKind kind;
    m_element_type = list_type.GetTemplateArgument(0, kind);
    m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
    m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
    return false;
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
{
    return true;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
    return ExtractIndexFromString(name.GetCString());
}

SyntheticChildrenFrontEnd*
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
    if (!valobj_sp)
        return NULL;
    return (new LibcxxStdListSyntheticFrontEnd(valobj_sp));
}
<commit_msg>Cache the incremental iterators as you traverse the list, so that you don't have to keep recomputing them<commit_after>//===-- LibCxxList.cpp ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "LibCxx.h"

#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace {

    class ListEntry
    {
    public:
        ListEntry() = default;
        ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
        ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
        ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}

        ListEntry
        next ()
        {
            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildAtIndexPath({0,1}));
        }

        ListEntry
        prev ()
        {
            if (!m_entry_sp)
                return ListEntry();
            return ListEntry(m_entry_sp->GetChildAtIndexPath({0,0}));
        }

        uint64_t
        value () const
        {
            if (!m_entry_sp)
                return 0;
            return m_entry_sp->GetValueAsUnsigned(0);
        }

        bool
        null()
        {
            return (value() == 0);
        }

        explicit operator bool ()
        {
            return GetEntry().get() != nullptr && null() == false;
        }

        ValueObjectSP
        GetEntry ()
        {
            return m_entry_sp;
        }

        void
        SetEntry (ValueObjectSP entry)
        {
            m_entry_sp = entry;
        }

        bool
        operator == (const ListEntry& rhs) const
        {
            return value() == rhs.value();
        }

        bool
        operator != (const ListEntry& rhs) const
        {
            return !(*this == rhs);
        }

    private:
        ValueObjectSP m_entry_sp;
    };

    class ListIterator
    {
    public:
        ListIterator() = default;
        ListIterator (ListEntry entry) : m_entry(entry) {}
        ListIterator (ValueObjectSP entry) : m_entry(entry) {}
        ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
        ListIterator (ValueObject* entry) : m_entry(entry) {}

        ValueObjectSP
        value ()
        {
            return m_entry.GetEntry();
        }

        ValueObjectSP
        advance (size_t count)
        {
            if (count == 0)
                return m_entry.GetEntry();
            if (count == 1)
            {
                next ();
                return m_entry.GetEntry();
            }
            while (count > 0)
            {
                next ();
                count--;
                if (m_entry.null())
                    return lldb::ValueObjectSP();
            }
            return m_entry.GetEntry();
        }

        bool
        operator == (const ListIterator& rhs) const
        {
            return (rhs.m_entry == m_entry);
        }

    protected:
        void
        next ()
        {
            m_entry = m_entry.next();
        }

        void
        prev ()
        {
            m_entry = m_entry.prev();
        }

    private:
        ListEntry m_entry;
    };

} // end anonymous namespace

namespace lldb_private {
    namespace formatters {
        class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd
        {
        public:
            LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

            ~LibcxxStdListSyntheticFrontEnd() override = default;

            size_t
            CalculateNumChildren() override;

            lldb::ValueObjectSP
            GetChildAtIndex(size_t idx) override;

            bool
            Update() override;

            bool
            MightHaveChildren() override;

            size_t
            GetIndexOfChildWithName(const ConstString &name) override;

        private:
            bool
            HasLoop(size_t count);

            size_t m_list_capping_size;
            static const bool g_use_loop_detect = true;

            size_t m_loop_detected; // The number of elements that have had loop detection run over them.
            ListEntry m_slow_runner; // Used for loop detection
            ListEntry m_fast_runner; // Used for loop detection

            lldb::addr_t m_node_address;
            ValueObject* m_head;
            ValueObject* m_tail;
            CompilerType m_element_type;
            size_t m_count;
            std::map<size_t,lldb::ValueObjectSP> m_children;
            std::map<size_t, ListIterator> m_iterators;
        };
    } // namespace formatters
} // namespace lldb_private

lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_list_capping_size(0),
m_loop_detected(0),
m_node_address(),
m_head(NULL),
m_tail(NULL),
m_element_type(),
m_count(UINT32_MAX),
m_children(),
m_iterators()
{
    if (valobj_sp)
        Update();
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count)
{
    if (g_use_loop_detect == false)
        return false;
    // don't bother checking for a loop if we won't actually need to jump nodes
    if (m_count < 2)
        return false;

    if (m_loop_detected == 0)
    {
        // This is the first time we are being run (after the last update). Set up the loop
        // invariant for the first element.
        m_slow_runner = ListEntry(m_head).next();
        m_fast_runner = m_slow_runner.next();
        m_loop_detected = 1;
    }

    // Loop invariant:
    // Loop detection has been run over the first m_loop_detected elements. If m_slow_runner ==
    // m_fast_runner then the loop has been detected after m_loop_detected elements.
    const size_t steps_to_run = std::min(count,m_count);
    while (m_loop_detected < steps_to_run
            && m_slow_runner
            && m_fast_runner
            && m_slow_runner != m_fast_runner) {

        m_slow_runner = m_slow_runner.next();
        m_fast_runner = m_fast_runner.next().next();
        m_loop_detected++;
    }
    if (count <= m_loop_detected)
        return false; // No loop in the first m_loop_detected elements.
    if (!m_slow_runner || !m_fast_runner)
        return false; // Reached the end of the list. Definitely no loops.
    return m_slow_runner == m_fast_runner;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
{
    if (m_count != UINT32_MAX)
        return m_count;
    if (!m_head || !m_tail || m_node_address == 0)
        return 0;
    ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
    if (size_alloc)
    {
        ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
        if (first)
        {
            m_count = first->GetValueAsUnsigned(UINT32_MAX);
        }
    }
    if (m_count != UINT32_MAX)
    {
        return m_count;
    }
    else
    {
        uint64_t next_val = m_head->GetValueAsUnsigned(0);
        uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
        if (next_val == 0 || prev_val == 0)
            return 0;
        if (next_val == m_node_address)
            return 0;
        if (next_val == prev_val)
            return 1;
        uint64_t size = 2;
        ListEntry current(m_head);
        while (current.next() && current.next().value() != m_node_address)
        {
            size++;
            current = current.next();
            if (size > m_list_capping_size)
                break;
        }
        return m_count = (size-1);
    }
}

lldb::ValueObjectSP
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
    if (idx >= CalculateNumChildren())
        return lldb::ValueObjectSP();

    if (!m_head || !m_tail || m_node_address == 0)
        return lldb::ValueObjectSP();

    auto cached = m_children.find(idx);
    if (cached != m_children.end())
        return cached->second;

    if (HasLoop(idx+1))
        return lldb::ValueObjectSP();

    size_t actual_advance = idx;

    ListIterator current(m_head);
    if (idx > 0)
    {
        auto cached_iterator = m_iterators.find(idx-1);
        if (cached_iterator != m_iterators.end())
        {
            current = cached_iterator->second;
            actual_advance = 1;
        }
    }

    ValueObjectSP current_sp(current.advance(actual_advance));
    if (!current_sp)
        return lldb::ValueObjectSP();

    m_iterators[idx] = current;

    current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
    if (!current_sp)
        return lldb::ValueObjectSP();
    // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
    DataExtractor data;
    Error error;
    current_sp->GetData(data, error);
    if (error.Fail())
        return lldb::ValueObjectSP();

    StreamString name;
    name.Printf("[%" PRIu64 "]", (uint64_t)idx);
    return (m_children[idx] = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
{
    m_children.clear();
    m_iterators.clear();
    m_head = m_tail = NULL;
    m_node_address = 0;
    m_count = UINT32_MAX;
    m_loop_detected = 0;
    m_slow_runner.SetEntry(nullptr);
    m_fast_runner.SetEntry(nullptr);

    Error err;
    ValueObjectSP backend_addr(m_backend.AddressOf(err));
    m_list_capping_size = 0;
    if (m_backend.GetTargetSP())
        m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
    if (m_list_capping_size == 0)
        m_list_capping_size = 255;
    if (err.Fail() || backend_addr.get() == NULL)
        return false;
    m_node_address = backend_addr->GetValueAsUnsigned(0);
    if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
        return false;
    ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
    if (!impl_sp)
        return false;
    CompilerType list_type = m_backend.GetCompilerType();
    if (list_type.IsReferenceType())
        list_type = list_type.GetNonReferenceType();

    if (list_type.GetNumTemplateArguments() == 0)
        return false;
    lldb::TemplateArgumentKind kind;
    m_element_type = list_type.GetTemplateArgument(0, kind);
    m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
    m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
    return false;
}

bool
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
{
    return true;
}

size_t
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
    return ExtractIndexFromString(name.GetCString());
}

SyntheticChildrenFrontEnd*
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
    if (!valobj_sp)
        return NULL;
    return (new LibcxxStdListSyntheticFrontEnd(valobj_sp));
}
<|endoftext|>


<commit_before>/*
 * Set_Mechanism_Units.cpp
 *
 *  Created on: 21 Feb 2018
 *      Author: detlev
 */

#include "../headers/Headers.hpp"

vector<int> Set_Mechanism_Units(string test_string) // Identify the units
{
	vector<int> Mechanism_Units(2);
	// default for A:  mol/cm^3 (I think...)
	// default for Ea: kcal/mol

	if(Test_If_Word_Found(test_string, "MOLECULES")) // enable case independent test
	{
		Mechanism_Units[0] = 0; // A in molecules cm^(-3)
	}

	if(Test_If_Word_Found(test_string, "KELVINS"))
	{
		Mechanism_Units[1] = 0; // Ea in Kelvins, great :)
	}

	if(Test_If_Word_Found(test_string, "MOLES"))
	{
		Mechanism_Units[0] = 1; // A in moles per cm^3
	}

	if(Test_If_Word_Found(test_string, " KCAL/MOL") || Test_If_Word_Found(test_string, "\tKCAL/MOL"))
	{
		Mechanism_Units[1] = 1; // Ea in kcal/mol
	}

	if(Test_If_Word_Found(test_string, " CAL/MOL") || Test_If_Word_Found(test_string, "\tCAL/MOL"))
	{
		Mechanism_Units[1] = 2; // Ea in kcal/mol
	}

	if(Test_If_Word_Found(test_string, " kJ/MOL") || Test_If_Word_Found(test_string, "\tkJ/MOL"))
	{
		Mechanism_Units[1] = 3; // Ea in kJ/mol
	}

	if(Test_If_Word_Found(test_string, " J/MOL") || Test_If_Word_Found(test_string, "\tJ/MOL"))
	{
		Mechanism_Units[1] = 4; // Ea in J/mol
	}

	return Mechanism_Units;
}

<commit_msg>group energies and Arrhenius parameters together - makes code clearer<commit_after>/*
 * Set_Mechanism_Units.cpp
 *
 *  Created on: 21 Feb 2018
 *      Author: detlev
 */

#include "../headers/Headers.hpp"

vector<int> Set_Mechanism_Units(string test_string) // Identify the units
{
	vector<int> Mechanism_Units(2);
	// default for A:  mol/cm^3 (I think...)
	// default for Ea: kcal/mol

	if(Test_If_Word_Found(test_string, "MOLECULES")) // enable case independent test
	{
		Mechanism_Units[0] = 0; // A in molecules cm^(-3)
	}

	if(Test_If_Word_Found(test_string, "MOLES"))
	{
		Mechanism_Units[0] = 1; // A in moles per cm^3
	}

	if(Test_If_Word_Found(test_string, "MOLE")) // assuming moles and mol is the same there
	{
		Mechanism_Units[0] = 1; // A in moles per cm^3
	}

	if(Test_If_Word_Found(test_string, "KELVINS"))
	{
		Mechanism_Units[1] = 0; // Ea in Kelvins, great :)
	}

	if(Test_If_Word_Found(test_string, " KCAL/MOL") || Test_If_Word_Found(test_string, "\tKCAL/MOL"))
	{
		Mechanism_Units[1] = 1; // Ea in kcal/mol
	}

	if(Test_If_Word_Found(test_string, " CAL/MOL") || Test_If_Word_Found(test_string, "\tCAL/MOL"))
	{
		Mechanism_Units[1] = 2; // Ea in kcal/mol
	}

	if(Test_If_Word_Found(test_string, " kJ/MOL") || Test_If_Word_Found(test_string, "\tkJ/MOL"))
	{
		Mechanism_Units[1] = 3; // Ea in kJ/mol
	}

	if(Test_If_Word_Found(test_string, " J/MOL") || Test_If_Word_Found(test_string, "\tJ/MOL"))
	{
		Mechanism_Units[1] = 4; // Ea in J/mol
	}

	return Mechanism_Units;
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: mapnik_parameters.cpp 17 2005-03-08 23:58:43Z pavlenko $

// boost
#include <boost/python.hpp>

// mapnik
#include <mapnik/params.hpp>

using mapnik::parameter;
using mapnik::parameters;

struct pickle_value : public boost::static_visitor<>
{
public:
    pickle_value( boost::python::list vals):
        vals_(vals) {}

    void operator () ( int val )
    {
        vals_.append(val);
    }

    void operator () ( double val )
    {
        vals_.append(val);
    }

    void operator () ( std::string val )
    {
        vals_.append(val);
    }

private:
    boost::python::list vals_;

};

struct parameter_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getinitargs(const parameter& p)
    {
        using namespace boost::python;
        return boost::python::make_tuple(p.first,boost::get<std::string>(p.second));
    }
};

struct parameters_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getstate(const parameters& p)
    {
        using namespace boost::python;
        dict d;
        parameters::const_iterator pos=p.begin();
        while(pos!=p.end())
        {
            boost::python::list vals;
            pickle_value serializer( vals );
            mapnik::value_holder val = pos->second;
            boost::apply_visitor( serializer, val );
            d[pos->first] = vals[0];
            ++pos;
        }
        return boost::python::make_tuple(d);
    }

    static void setstate(parameters& p, boost::python::tuple state)
    {
        using namespace boost::python;
        if (len(state) != 1)
        {
            PyErr_SetObject(PyExc_ValueError,
                            ("expected 1-item tuple in call to __setstate__; got %s"
                             % state).ptr()
                );
            throw_error_already_set();
        }

        dict d = extract<dict>(state[0]);
        boost::python::list keys = d.keys();
        for (int i=0; i<len(keys); ++i)
        {
            std::string key = extract<std::string>(keys[i]);
            object obj = d[key];
            extract<std::string> ex0(obj);
            extract<int> ex1(obj);
            extract<double> ex2(obj);

            if (ex0.check())
            {
                p[key] = ex0();
            }
            else if (ex1.check())
            {
                p[key] = ex1();
            }
            else if (ex2.check())
            {
                p[key] = ex2();
            }

            /*
              extract_value serializer( p, key );
              mapnik::value_holder val = extract<mapnik::value_holder>(d[key]);
              boost::apply_visitor( serializer, val );
            */
        }
    }
};

boost::python::dict dict_params(parameters& p)
{
    boost::python::dict d;
    parameters::const_iterator pos=p.begin();
    while(pos!=p.end())
    {
        boost::python::list vals;
        pickle_value serializer( vals );
        mapnik::value_holder val = pos->second;
        boost::apply_visitor( serializer, val );
        d[pos->first] = vals[0];
        ++pos;
    }
    return d;
}

boost::python::list list_params(parameters& p)
{
    boost::python::list l;
    parameters::const_iterator pos=p.begin();
    while(pos!=p.end())
    {
        boost::python::list vals;
        pickle_value serializer( vals );
        mapnik::value_holder val = pos->second;
        boost::apply_visitor( serializer, val );
        l.append(boost::python::make_tuple(pos->first,vals[0]));
        ++pos;
    }
    return l;
}

boost::python::dict dict_param(parameter& p)
{
    boost::python::dict d;
    d[p.first] = boost::get<std::string>(p.second);
    return d;
}

boost::python::tuple tuple_param(parameter& p)
{
    return boost::python::make_tuple(p.first,boost::get<std::string>(p.second));
}

void export_parameters()
{
    using namespace boost::python;
    class_<parameter>("Parameter",init<std::string,std::string>())
        .def_pickle(parameter_pickle_suite())
        .def("as_dict",dict_param)
        .def("as_tuple",tuple_param)
        ;

    class_<parameters>("Parameters",init<>())
        .def_pickle(parameters_pickle_suite())
        .def("as_dict",dict_params)
        .def("as_list",list_params)
        ;
}
<commit_msg>python: refactor interface to mapnik::parameters using poor man's indexingapproach - long term todo is merge mapnik::value_holder and mapnik::value to make this cleaner - refs #976<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// boost
#include <boost/python.hpp>
#include <boost/make_shared.hpp>

// mapnik
#include <mapnik/params.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/value.hpp>

using mapnik::parameter;
using mapnik::parameters;

struct parameter_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getinitargs(const parameter& p)
    {
        using namespace boost::python;
        return boost::python::make_tuple(p.first,p.second);
    }
};

struct parameters_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getstate(const parameters& p)
    {
        using namespace boost::python;
        dict d;
        parameters::const_iterator pos=p.begin();
        while(pos!=p.end())
        {
            d[pos->first] = pos->second;
            ++pos;
        }
        return boost::python::make_tuple(d);
    }

    static void setstate(parameters& p, boost::python::tuple state)
    {
        using namespace boost::python;
        if (len(state) != 1)
        {
            PyErr_SetObject(PyExc_ValueError,
                            ("expected 1-item tuple in call to __setstate__; got %s"
                             % state).ptr()
                );
            throw_error_already_set();
        }

        dict d = extract<dict>(state[0]);
        boost::python::list keys = d.keys();
        for (int i=0; i<len(keys); ++i)
        {
            std::string key = extract<std::string>(keys[i]);
            object obj = d[key];
            extract<std::string> ex0(obj);
            extract<int> ex1(obj);
            extract<double> ex2(obj);
            extract<UnicodeString> ex3(obj);

            // TODO - this is never hit - we need proper python string -> std::string to get invoked here
            if (ex0.check())
            {
                p[key] = ex0();
            }
            else if (ex1.check())
            {
                p[key] = ex1();
            }
            else if (ex2.check())
            {
                p[key] = ex2();
            }
            else if (ex3.check())
            {
                std::string buffer;
                mapnik::to_utf8(ex3(),buffer);
                p[key] = buffer;
            }
            else
            {
                std::clog <<  "could not unpickle key: " << key << "\n";
            }
        }
    }
};

mapnik::value_holder get_params_by_key1(mapnik::parameters const& p, std::string const& key)
{
    parameters::const_iterator pos = p.find(key);
    if (pos != p.end())
    {
        // will be auto-converted to proper python type by `mapnik_params_to_python`
        return pos->second;
    }
    return mapnik::value_null();
}

mapnik::value_holder get_params_by_key2(mapnik::parameters const& p, std::string const& key)
{
    parameters::const_iterator pos = p.find(key);
    if (pos == p.end())
    {
        PyErr_SetString(PyExc_KeyError, key.c_str());
        boost::python::throw_error_already_set();
    }
    // will be auto-converted to proper python type by `mapnik_params_to_python`
    return pos->second;
}

mapnik::parameter get_params_by_index(mapnik::parameters const& p, int index)
{
    if (index < 0 || index > p.size())
    {
        PyErr_SetString(PyExc_IndexError, "Index is out of range");
        throw boost::python::error_already_set();
    }

    parameters::const_iterator itr = p.begin();
    parameters::const_iterator end = p.end();

    unsigned idx = 0;
    while (itr != p.end())
    {
        if (idx == index)
        {
            return *itr;
        }
        ++idx;
        ++itr;
    }
    PyErr_SetString(PyExc_IndexError, "Index is out of range");
    throw boost::python::error_already_set();
}

void add_parameter(mapnik::parameters & p, mapnik::parameter const& param)
{
    p[param.first] = param.second;
}

mapnik::value_holder get_param(mapnik::parameter const& p, int index)
{
    if (index == 0)
    {
        return p.first;
    }
    else if (index == 1)
    {
        return p.second;
    }
    else
    {
        PyErr_SetString(PyExc_IndexError, "Index is out of range");
        throw boost::python::error_already_set();
    }
}

boost::shared_ptr<mapnik::parameter> create_parameter_from_string(std::string const& key, std::string const& value)
{
    return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
}

boost::shared_ptr<mapnik::parameter> create_parameter_from_int(std::string const& key, int value)
{
    return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
}

boost::shared_ptr<mapnik::parameter> create_parameter_from_float(std::string const& key, double value)
{
    return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
}

void export_parameters()
{
    using namespace boost::python;
    class_<parameter,boost::shared_ptr<parameter> >("Parameter",no_init)
        .def("__init__", make_constructor(create_parameter_from_string),
             "Create a mapnik.Parameter from a pair of values, the first being a string\n"
             "and the second being either a string, and integer, or a float")
        .def("__init__", make_constructor(create_parameter_from_int),
             "Create a mapnik.Parameter from a pair of values, the first being a string\n"
             "and the second being either a string, and integer, or a float")
        .def("__init__", make_constructor(create_parameter_from_float),
             "Create a mapnik.Parameter from a pair of values, the first being a string\n"
             "and the second being either a string, and integer, or a float")
        .def_pickle(parameter_pickle_suite())
        .def("__getitem__",get_param)
        ;

    class_<parameters>("Parameters",init<>())
        .def_pickle(parameters_pickle_suite())
        .def("get",get_params_by_key1)
        .def("__getitem__",get_params_by_key2)
        .def("__getitem__",get_params_by_index)
        .def("__len__",&parameters::size)
        .def("append",add_parameter)
        .def("iteritems",iterator<parameters>())
        ;
}
<|endoftext|>