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

#include "index/txindex.h"
#include "blockstorage/blockstorage.h"
#include "blockstorage/sequential_files.h"
#include "chainparams.h"
#include "init.h"
#include "tinyformat.h"
#include "ui_interface.h"
#include "util.h"
#include "validation/validation.h"

constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds

std::unique_ptr<TxIndex> g_txindex;

template <typename... Args>
static void FatalError(const char *fmt, const Args &... args)
{
    std::string strMessage = tfm::format(fmt, args...);
    LOGA("*** %s\n", strMessage);
    uiInterface.ThreadSafeMessageBox(
        "Error: A fatal internal error occurred, see debug.log for details", "", CClientUIInterface::MSG_ERROR);
    StartShutdown();
}

TxIndex::TxIndex(std::unique_ptr<TxIndexDB> _db) : db(std::move(_db)), fSynced(false), pbestindex(nullptr) {}
TxIndex::~TxIndex() {}
bool TxIndex::Init()
{
    LOCK(cs_main);

    // Attempt to migrate txindex from the old database to the new one. Even if
    // chain_tip is null, the node could be reindexing and we still want to
    // delete txindex records in the old database.
    if (!db->MigrateData(*pblocktree, chainActive.GetLocator()))
    {
        return false;
    }

    CBlockLocator locator;
    if (!db->ReadBestBlock(locator))
    {
        locator.SetNull();
    }

    pbestindex = FindForkInGlobalIndex(chainActive, locator);
    fSynced = pbestindex.load() == chainActive.Tip();
    return true;
}

static const CBlockIndex *NextSyncBlock(const CBlockIndex *pindex_prev)
{
    AssertLockHeld(cs_main);

    if (!pindex_prev)
    {
        return chainActive.Genesis();
    }

    const CBlockIndex *pindex = chainActive.Next(pindex_prev);
    if (pindex)
    {
        return pindex;
    }

    return chainActive.Next(chainActive.FindFork(pindex_prev));
}

void TxIndex::ThreadSync()
{
    CBlockIndex *pindex = pbestindex.load();
    if (!fSynced)
    {
        auto &consensus_params = Params().GetConsensus();

        int64_t last_log_time = 0;
        int64_t last_locator_write_time = 0;
        while (true)
        {
            if (shutdown_threads.load() == true)
            {
                WriteBestBlock(pindex);
                return;
            }

            {
                LOCK(cs_main);
                const CBlockIndex *pindex_next = NextSyncBlock(pindex);
                if (!pindex_next)
                {
                    WriteBestBlock(pindex);
                    pbestindex = pindex;
                    fSynced = true;
                    break;
                }
                pindex = const_cast<CBlockIndex *>(pindex_next);
            }

            int64_t current_time = GetTime();
            if (last_log_time + SYNC_LOG_INTERVAL < current_time)
            {
                LOGA("Syncing txindex with block chain from height %d\n", pindex->nHeight);
                last_log_time = current_time;
            }

            if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time)
            {
                WriteBestBlock(pindex);
                last_locator_write_time = current_time;
            }

            CBlock block;
            if (!ReadBlockFromDisk(block, pindex, consensus_params))
            {
                FatalError("%s: Failed to read block %s from disk", __func__, pindex->GetBlockHash().ToString());
                return;
            }
            if (!WriteBlock(block, pindex))
            {
                FatalError(
                    "%s: Failed to write block %s to tx index database", __func__, pindex->GetBlockHash().ToString());
                return;
            }
        }
    }

    if (pindex)
    {
        LOGA("txindex is enabled at height %d\n", pindex->nHeight);
    }
    else
    {
        LOGA("txindex is enabled\n");
    }
}

bool TxIndex::WriteBlock(const CBlock &block, const CBlockIndex *pindex)
{
    CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
    std::vector<std::pair<uint256, CDiskTxPos> > vPos;
    vPos.reserve(block.vtx.size());
    for (const auto &tx : block.vtx)
    {
        vPos.emplace_back(tx->GetHash(), pos);
        pos.nTxOffset += ::GetSerializeSize(*tx, SER_DISK, CLIENT_VERSION);
    }
    return db->WriteTxs(vPos);
}

bool TxIndex::WriteBestBlock(CBlockIndex *block_index)
{
    LOCK(cs_main);
    if (!db->WriteBestBlock(chainActive.GetLocator(block_index)))
    {
        return error("%s: Failed to write locator to disk", __func__);
    }
    return true;
}

void TxIndex::BlockConnected(const CBlock &block, CBlockIndex *pindex)
{
    if (!fSynced.load())
    {
        return;
    }

    const CBlockIndex *pbest = pbestindex.load();
    if (!pbest)
    {
        if (pindex->nHeight != 0)
        {
            FatalError("%s: First block connected is not the genesis block (height=%d)", __func__, pindex->nHeight);
            return;
        }
    }
    else
    {
        // Ensure block connects to an ancestor of the current best block. This should be the case
        // most of the time, but may not be immediately after the the sync thread catches up and sets
        // fSynced. Consider the case where there is a reorg and the blocks on the stale branch are
        // in the ValidationInterface queue backlog even after the sync thread has caught up to the
        // new chain tip. In this unlikely event, log a warning and let the queue clear.
        if (pbest->GetAncestor(pindex->nHeight - 1) != pindex->pprev)
        {
            LOGA("%s: WARNING: Block %s does not connect to an ancestor of " /* Continued */
                 "known best chain (tip=%s); not updating txindex\n",
                __func__, pindex->GetBlockHash().ToString(), pbest->GetBlockHash().ToString());
            return;
        }
    }

    if (WriteBlock(block, pindex))
    {
        pbestindex = pindex;

        if (WriteBestBlock(pindex))
        {
            error("%s: Failed to write locator to disk", __func__);
        }
    }
    else
    {
        FatalError("%s: Failed to write block %s to txindex", __func__, pindex->GetBlockHash().ToString());
        return;
    }
}

bool TxIndex::BlockUntilSyncedToCurrentChain()
{
    AssertLockNotHeld(cs_main);

    if (!fSynced)
    {
        return false;
    }

    LOGA("%s: txindex is catching up on block notifications\n", __func__);
    return true;
}

bool TxIndex::FindTx(const uint256 &txhash, uint256 &blockhash, CTransactionRef ptx) const
{
    AssertLockHeld(cs_main);

    CDiskTxPos postx;
    if (!db->ReadTxPos(txhash, postx))
        return false;

    CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
    if (file.IsNull())
        return error("%s: OpenBlockFile failed", __func__);
    CBlockHeader header;
    try
    {
        file >> header;
        fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
        file >> ptx;
    }
    catch (const std::exception &e)
    {
        return error("%s: Deserialize or I/O error - %s", __func__, e.what());
    }
    blockhash = header.GetHash();
    if (ptx->GetHash() != txhash)
        return error("%s: txid mismatch", __func__);

    return true;
}
void TxIndex::Start()
{
    // Need to register this ValidationInterface before running Init(), so that
    // callbacks are not missed if Init sets fSynced to true.
    RegisterValidationInterface(this);
    if (!Init())
    {
        FatalError("%s: txindex failed to initialize", __func__);
        return;
    }

    syncthread = std::thread(&TraceThread<std::function<void()> >, "txindex", std::bind(&TxIndex::ThreadSync, this));
}

void TxIndex::Stop()
{
    shutdown_threads.store(true);
    UnregisterValidationInterface(this);
    if (syncthread.joinable())
    {
        syncthread.join();
    }
}
<commit_msg>Set the fReindex flag when starting txindex<commit_after>// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "index/txindex.h"
#include "blockstorage/blockstorage.h"
#include "blockstorage/sequential_files.h"
#include "chainparams.h"
#include "init.h"
#include "tinyformat.h"
#include "ui_interface.h"
#include "util.h"
#include "validation/validation.h"

constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds

std::unique_ptr<TxIndex> g_txindex;

template <typename... Args>
static void FatalError(const char *fmt, const Args &... args)
{
    std::string strMessage = tfm::format(fmt, args...);
    LOGA("*** %s\n", strMessage);
    uiInterface.ThreadSafeMessageBox(
        "Error: A fatal internal error occurred, see debug.log for details", "", CClientUIInterface::MSG_ERROR);
    StartShutdown();
}

TxIndex::TxIndex(std::unique_ptr<TxIndexDB> _db) : db(std::move(_db)), fSynced(false), pbestindex(nullptr) {}
TxIndex::~TxIndex() {}
bool TxIndex::Init()
{
    LOCK(cs_main);

    // Attempt to migrate txindex from the old database to the new one. Even if
    // chain_tip is null, the node could be reindexing and we still want to
    // delete txindex records in the old database.
    if (!db->MigrateData(*pblocktree, chainActive.GetLocator()))
    {
        return false;
    }

    CBlockLocator locator;
    if (!db->ReadBestBlock(locator))
    {
        locator.SetNull();
    }

    pbestindex = FindForkInGlobalIndex(chainActive, locator);
    fSynced = pbestindex.load() == chainActive.Tip();
    return true;
}

static const CBlockIndex *NextSyncBlock(const CBlockIndex *pindex_prev)
{
    AssertLockHeld(cs_main);

    if (!pindex_prev)
    {
        return chainActive.Genesis();
    }

    const CBlockIndex *pindex = chainActive.Next(pindex_prev);
    if (pindex)
    {
        return pindex;
    }

    return chainActive.Next(chainActive.FindFork(pindex_prev));
}

void TxIndex::ThreadSync()
{
    if (fReindex)
        return;

    CBlockIndex *pindex = pbestindex.load();
    if (!fSynced)
    {
        auto &consensus_params = Params().GetConsensus();

        int64_t last_log_time = 0;
        int64_t last_locator_write_time = 0;
        while (true)
        {
            if (shutdown_threads.load() == true)
            {
                WriteBestBlock(pindex);
                return;
            }

            {
                LOCK(cs_main);
                const CBlockIndex *pindex_next = NextSyncBlock(pindex);
                if (!pindex_next)
                {
                    WriteBestBlock(pindex);
                    pbestindex = pindex;
                    fSynced = true;
                    break;
                }
                pindex = const_cast<CBlockIndex *>(pindex_next);
            }

            int64_t current_time = GetTime();
            if (last_log_time + SYNC_LOG_INTERVAL < current_time)
            {
                LOGA("Syncing txindex with block chain from height %d\n", pindex->nHeight);
                last_log_time = current_time;
            }

            if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time)
            {
                WriteBestBlock(pindex);
                last_locator_write_time = current_time;
            }

            CBlock block;
            if (!ReadBlockFromDisk(block, pindex, consensus_params))
            {
                FatalError("%s: Failed to read block %s from disk", __func__, pindex->GetBlockHash().ToString());
                return;
            }
            if (!WriteBlock(block, pindex))
            {
                FatalError(
                    "%s: Failed to write block %s to tx index database", __func__, pindex->GetBlockHash().ToString());
                return;
            }
        }
    }

    if (pindex)
    {
        LOGA("txindex is enabled at height %d\n", pindex->nHeight);
    }
    else
    {
        LOGA("txindex is enabled\n");
    }
}

bool TxIndex::WriteBlock(const CBlock &block, const CBlockIndex *pindex)
{
    CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
    std::vector<std::pair<uint256, CDiskTxPos> > vPos;
    vPos.reserve(block.vtx.size());
    for (const auto &tx : block.vtx)
    {
        vPos.emplace_back(tx->GetHash(), pos);
        pos.nTxOffset += ::GetSerializeSize(*tx, SER_DISK, CLIENT_VERSION);
    }
    return db->WriteTxs(vPos);
}

bool TxIndex::WriteBestBlock(CBlockIndex *block_index)
{
    LOCK(cs_main);
    if (!db->WriteBestBlock(chainActive.GetLocator(block_index)))
    {
        return error("%s: Failed to write locator to disk", __func__);
    }
    return true;
}

void TxIndex::BlockConnected(const CBlock &block, CBlockIndex *pindex)
{
    if (!fSynced.load() && !fReindex)
    {
        return;
    }

    if (WriteBlock(block, pindex))
    {
        pbestindex = pindex;

        if (WriteBestBlock(pindex))
        {
            error("%s: Failed to write locator to disk", __func__);
        }
    }
    else
    {
        FatalError("%s: Failed to write block %s to txindex", __func__, pindex->GetBlockHash().ToString());
        return;
    }
}

bool TxIndex::BlockUntilSyncedToCurrentChain()
{
    AssertLockNotHeld(cs_main);

    if (!fSynced)
    {
        return false;
    }

    LOGA("%s: txindex is catching up on block notifications\n", __func__);
    return true;
}

bool TxIndex::FindTx(const uint256 &txhash, uint256 &blockhash, CTransactionRef ptx) const
{
    AssertLockHeld(cs_main);

    CDiskTxPos postx;
    if (!db->ReadTxPos(txhash, postx))
        return false;

    CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
    if (file.IsNull())
        return error("%s: OpenBlockFile failed", __func__);
    CBlockHeader header;
    try
    {
        file >> header;
        fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
        file >> ptx;
    }
    catch (const std::exception &e)
    {
        return error("%s: Deserialize or I/O error - %s", __func__, e.what());
    }
    blockhash = header.GetHash();
    if (ptx->GetHash() != txhash)
        return error("%s: txid mismatch", __func__);

    return true;
}
void TxIndex::Start()
{
    // Need to register this ValidationInterface before running Init(), so that
    // callbacks are not missed if Init sets fSynced to true.
    RegisterValidationInterface(this);
    if (!Init())
    {
        FatalError("%s: txindex failed to initialize", __func__);
        return;
    }

    syncthread = std::thread(&TraceThread<std::function<void()> >, "txindex", std::bind(&TxIndex::ThreadSync, this));
}

void TxIndex::Stop()
{
    shutdown_threads.store(true);
    UnregisterValidationInterface(this);
    if (syncthread.joinable())
    {
        syncthread.join();
    }
}
<|endoftext|>


<commit_before>#include <wayfire/view.hpp>
#include <wayfire/plugin.hpp>
#include <wayfire/output.hpp>
#include <wayfire/workspace-manager.hpp>
#include <wayfire/util/log.hpp>
#include "wm-actions-signals.hpp"

class wayfire_wm_actions_t : public wf::plugin_interface_t
{
    nonstd::observer_ptr<wf::sublayer_t> always_above;
    bool showdesktop_active = false;

    wf::option_wrapper_t<wf::activatorbinding_t> toggle_showdesktop{
        "wm-actions/toggle_showdesktop"};
    wf::option_wrapper_t<wf::activatorbinding_t> minimize{
        "wm-actions/minimize"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_maximize{
        "wm-actions/toggle_maximize"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_above{
        "wm-actions/toggle_always_on_top"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_fullscreen{
        "wm-actions/toggle_fullscreen"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_sticky{
        "wm-actions/toggle_sticky"};

    bool toggle_keep_above(wayfire_view view)
    {
        if (!view || !output->can_activate_plugin(this->grab_interface))
        {
            return false;
        }

        if (view->has_data("wm-actions-above"))
        {
            output->workspace->add_view(view,
                (wf::layer_t)output->workspace->get_view_layer(view));
            view->erase_data("wm-actions-above");
        } else
        {
            output->workspace->add_view_to_sublayer(view, always_above);
            view->store_data(std::make_unique<wf::custom_data_t>(),
                "wm-actions-above");
        }

        wf::wm_actions_above_changed data;
        data.view = view;
        output->emit_signal("wm-actions-above-changed", &data);

        return true;
    }

    /**
     * Find the selected toplevel view, or nullptr if the selected
     * view is not toplevel.
     */
    wayfire_view choose_view(wf::activator_source_t source)
    {
        wayfire_view view;
        if (source == wf::activator_source_t::BUTTONBINDING)
        {
            view = wf::get_core().get_cursor_focus_view();
        }

        view = output->get_active_view();
        if (!view || (view->role != wf::VIEW_ROLE_TOPLEVEL))
        {
            return nullptr;
        } else
        {
            return view;
        }
    }

    /**
     * Calling a specific view / specific keep_above action via signal
     */
    wf::signal_connection_t on_toggle_above_signal =
    {[=] (wf::signal_data_t *data)
        {
            auto signal = static_cast<wf::wm_actions_toggle_above*>(data);

            if (!toggle_keep_above(signal->view))
            {
                LOG(wf::log::LOG_LEVEL_DEBUG,
                    "view above action failed via signal.");
            }
        }
    };

    /**
     * Ensures views marked as above are still above
     * if their output changes.
     */
    wf::signal_connection_t on_view_output_changed
    {[=] (wf::signal_data_t *data)
        {
            auto signal = static_cast<wf::view_moved_to_output_signal*>(data);
            if (signal->new_output != output)
            {
                return;
            }

            auto view = signal->view;

            if (!view)
            {
                return;
            }

            if (view->has_data("wm-actions-above"))
            {
                output->workspace->add_view_to_sublayer(view, always_above);
            }
        }
    };

    /**
     * Ensures views marked as above are still above
     * if they are minimized and unminimized.
     */
    wf::signal_connection_t on_view_minimized
    {[=] (wf::signal_data_t *data)
        {
            auto signal = static_cast<wf::view_minimized_signal*>(data);
            auto view   = signal->view;

            if (!view)
            {
                return;
            }

            if (view->get_output() != output)
            {
                return;
            }

            if (view->has_data("wm-actions-above") && (signal->state == false))
            {
                output->workspace->add_view_to_sublayer(view, always_above);
            }
        }
    };

    /**
     * Disables show desktop if the workspace is changed or any view is
     * attached, mapped or unminimized.
     */
    wf::signal_connection_t view_attached = [this] (wf::signal_data_t *data)
    {
        auto view = get_signaled_view(data);
        if ((view->role != wf::VIEW_ROLE_TOPLEVEL) || !view->is_mapped())
        {
            return;
        }

        disable_showdesktop();
    };

    wf::signal_connection_t workspace_changed = [this] (wf::signal_data_t *data)
    {
        disable_showdesktop();
    };

    wf::signal_connection_t view_minimized = [this] (wf::signal_data_t *data)
    {
        auto ev = static_cast<wf::view_minimized_signal*>(data);

        if ((ev->view->role != wf::VIEW_ROLE_TOPLEVEL) || !ev->view->is_mapped())
        {
            return;
        }

        if (!ev->state)
        {
            disable_showdesktop();
        }
    };

    /**
     * Execute for_view on the selected view, if available.
     */
    bool execute_for_selected_view(wf::activator_source_t source,
        std::function<bool(wayfire_view)> for_view)
    {
        auto view = choose_view(source);
        if (!view || !output->can_activate_plugin(this->grab_interface))
        {
            return false;
        }

        return for_view(view);
    }

    /**
     * The default activator bindings.
     */
    wf::activator_callback on_toggle_above = [=] (auto ev) -> bool
    {
        auto view = choose_view(ev.source);

        return toggle_keep_above(view);
    };

    wf::activator_callback on_minimize = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->minimize_request(!view->minimized);
            return true;
        });
    };

    wf::activator_callback on_toggle_maximize = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->tile_request(view->tiled_edges ==
                wf::TILED_EDGES_ALL ? 0 : wf::TILED_EDGES_ALL);
            return true;
        });
    };

    wf::activator_callback on_toggle_fullscreen = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->fullscreen_request(view->get_output(), !view->fullscreen);
            return true;
        });
    };

    wf::activator_callback on_toggle_sticky = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->set_sticky(view->sticky ^ 1);
            return true;
        });
    };

    wf::activator_callback on_toggle_showdesktop = [=] (auto ev) -> bool
    {
        showdesktop_active = !showdesktop_active;

        if (showdesktop_active)
        {
            for (auto& view : output->workspace->get_views_in_layer(wf::WM_LAYERS))
            {
                if (!view->minimized)
                {
                    view->minimize_request(true);
                    view->store_data(
                        std::make_unique<wf::custom_data_t>(),
                        "wm-actions-showdesktop");
                }
            }

            output->connect_signal("view-layer-attached", &view_attached);
            output->connect_signal("view-mapped", &view_attached);
            output->connect_signal("workspace-changed", &workspace_changed);
            output->connect_signal("view-minimized", &view_minimized);
            return true;
        }

        disable_showdesktop();

        return true;
    };

    void disable_showdesktop()
    {
        view_attached.disconnect();
        workspace_changed.disconnect();
        view_minimized.disconnect();

        for (auto& view : output->workspace->get_views_in_layer(wf::ALL_LAYERS))
        {
            if (view->has_data("wm-actions-showdesktop"))
            {
                view->erase_data("wm-actions-showdesktop");
                view->minimize_request(false);
            }
        }

        showdesktop_active = false;
    }

  public:
    void init() override
    {
        always_above = output->workspace->create_sublayer(
            wf::LAYER_WORKSPACE, wf::SUBLAYER_DOCKED_ABOVE);
        output->add_activator(toggle_showdesktop, &on_toggle_showdesktop);
        output->add_activator(minimize, &on_minimize);
        output->add_activator(toggle_maximize, &on_toggle_maximize);
        output->add_activator(toggle_above, &on_toggle_above);
        output->add_activator(toggle_fullscreen, &on_toggle_fullscreen);
        output->add_activator(toggle_sticky, &on_toggle_sticky);
        output->connect_signal("wm-actions-toggle-above", &on_toggle_above_signal);
        output->connect_signal("view-minimized", &on_view_minimized);
        wf::get_core().connect_signal("view-moved-to-output",
            &on_view_output_changed);
    }

    void fini() override
    {
        auto always_on_top_views =
            output->workspace->get_views_in_sublayer(always_above);

        for (auto view : always_on_top_views)
        {
            view->erase_data("wm-actions-above");
        }

        output->workspace->destroy_sublayer(always_above);
        output->rem_binding(&on_toggle_showdesktop);
        output->rem_binding(&on_minimize);
        output->rem_binding(&on_toggle_maximize);
        output->rem_binding(&on_toggle_above);
        output->rem_binding(&on_toggle_fullscreen);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_wm_actions_t);
<commit_msg>Fixing missing binding removal<commit_after>#include <wayfire/view.hpp>
#include <wayfire/plugin.hpp>
#include <wayfire/output.hpp>
#include <wayfire/workspace-manager.hpp>
#include <wayfire/util/log.hpp>
#include "wm-actions-signals.hpp"

class wayfire_wm_actions_t : public wf::plugin_interface_t
{
    nonstd::observer_ptr<wf::sublayer_t> always_above;
    bool showdesktop_active = false;

    wf::option_wrapper_t<wf::activatorbinding_t> toggle_showdesktop{
        "wm-actions/toggle_showdesktop"};
    wf::option_wrapper_t<wf::activatorbinding_t> minimize{
        "wm-actions/minimize"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_maximize{
        "wm-actions/toggle_maximize"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_above{
        "wm-actions/toggle_always_on_top"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_fullscreen{
        "wm-actions/toggle_fullscreen"};
    wf::option_wrapper_t<wf::activatorbinding_t> toggle_sticky{
        "wm-actions/toggle_sticky"};

    bool toggle_keep_above(wayfire_view view)
    {
        if (!view || !output->can_activate_plugin(this->grab_interface))
        {
            return false;
        }

        if (view->has_data("wm-actions-above"))
        {
            output->workspace->add_view(view,
                (wf::layer_t)output->workspace->get_view_layer(view));
            view->erase_data("wm-actions-above");
        } else
        {
            output->workspace->add_view_to_sublayer(view, always_above);
            view->store_data(std::make_unique<wf::custom_data_t>(),
                "wm-actions-above");
        }

        wf::wm_actions_above_changed data;
        data.view = view;
        output->emit_signal("wm-actions-above-changed", &data);

        return true;
    }

    /**
     * Find the selected toplevel view, or nullptr if the selected
     * view is not toplevel.
     */
    wayfire_view choose_view(wf::activator_source_t source)
    {
        wayfire_view view;
        if (source == wf::activator_source_t::BUTTONBINDING)
        {
            view = wf::get_core().get_cursor_focus_view();
        }

        view = output->get_active_view();
        if (!view || (view->role != wf::VIEW_ROLE_TOPLEVEL))
        {
            return nullptr;
        } else
        {
            return view;
        }
    }

    /**
     * Calling a specific view / specific keep_above action via signal
     */
    wf::signal_connection_t on_toggle_above_signal =
    {[=] (wf::signal_data_t *data)
        {
            auto signal = static_cast<wf::wm_actions_toggle_above*>(data);

            if (!toggle_keep_above(signal->view))
            {
                LOG(wf::log::LOG_LEVEL_DEBUG,
                    "view above action failed via signal.");
            }
        }
    };

    /**
     * Ensures views marked as above are still above
     * if their output changes.
     */
    wf::signal_connection_t on_view_output_changed
    {[=] (wf::signal_data_t *data)
        {
            auto signal = static_cast<wf::view_moved_to_output_signal*>(data);
            if (signal->new_output != output)
            {
                return;
            }

            auto view = signal->view;

            if (!view)
            {
                return;
            }

            if (view->has_data("wm-actions-above"))
            {
                output->workspace->add_view_to_sublayer(view, always_above);
            }
        }
    };

    /**
     * Ensures views marked as above are still above
     * if they are minimized and unminimized.
     */
    wf::signal_connection_t on_view_minimized
    {[=] (wf::signal_data_t *data)
        {
            auto signal = static_cast<wf::view_minimized_signal*>(data);
            auto view   = signal->view;

            if (!view)
            {
                return;
            }

            if (view->get_output() != output)
            {
                return;
            }

            if (view->has_data("wm-actions-above") && (signal->state == false))
            {
                output->workspace->add_view_to_sublayer(view, always_above);
            }
        }
    };

    /**
     * Disables show desktop if the workspace is changed or any view is
     * attached, mapped or unminimized.
     */
    wf::signal_connection_t view_attached = [this] (wf::signal_data_t *data)
    {
        auto view = get_signaled_view(data);
        if ((view->role != wf::VIEW_ROLE_TOPLEVEL) || !view->is_mapped())
        {
            return;
        }

        disable_showdesktop();
    };

    wf::signal_connection_t workspace_changed = [this] (wf::signal_data_t *data)
    {
        disable_showdesktop();
    };

    wf::signal_connection_t view_minimized = [this] (wf::signal_data_t *data)
    {
        auto ev = static_cast<wf::view_minimized_signal*>(data);

        if ((ev->view->role != wf::VIEW_ROLE_TOPLEVEL) || !ev->view->is_mapped())
        {
            return;
        }

        if (!ev->state)
        {
            disable_showdesktop();
        }
    };

    /**
     * Execute for_view on the selected view, if available.
     */
    bool execute_for_selected_view(wf::activator_source_t source,
        std::function<bool(wayfire_view)> for_view)
    {
        auto view = choose_view(source);
        if (!view || !output->can_activate_plugin(this->grab_interface))
        {
            return false;
        }

        return for_view(view);
    }

    /**
     * The default activator bindings.
     */
    wf::activator_callback on_toggle_above = [=] (auto ev) -> bool
    {
        auto view = choose_view(ev.source);

        return toggle_keep_above(view);
    };

    wf::activator_callback on_minimize = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->minimize_request(!view->minimized);
            return true;
        });
    };

    wf::activator_callback on_toggle_maximize = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->tile_request(view->tiled_edges ==
                wf::TILED_EDGES_ALL ? 0 : wf::TILED_EDGES_ALL);
            return true;
        });
    };

    wf::activator_callback on_toggle_fullscreen = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->fullscreen_request(view->get_output(), !view->fullscreen);
            return true;
        });
    };

    wf::activator_callback on_toggle_sticky = [=] (auto ev) -> bool
    {
        return execute_for_selected_view(ev.source, [] (wayfire_view view)
        {
            view->set_sticky(view->sticky ^ 1);
            return true;
        });
    };

    wf::activator_callback on_toggle_showdesktop = [=] (auto ev) -> bool
    {
        showdesktop_active = !showdesktop_active;

        if (showdesktop_active)
        {
            for (auto& view : output->workspace->get_views_in_layer(wf::WM_LAYERS))
            {
                if (!view->minimized)
                {
                    view->minimize_request(true);
                    view->store_data(
                        std::make_unique<wf::custom_data_t>(),
                        "wm-actions-showdesktop");
                }
            }

            output->connect_signal("view-layer-attached", &view_attached);
            output->connect_signal("view-mapped", &view_attached);
            output->connect_signal("workspace-changed", &workspace_changed);
            output->connect_signal("view-minimized", &view_minimized);
            return true;
        }

        disable_showdesktop();

        return true;
    };

    void disable_showdesktop()
    {
        view_attached.disconnect();
        workspace_changed.disconnect();
        view_minimized.disconnect();

        for (auto& view : output->workspace->get_views_in_layer(wf::ALL_LAYERS))
        {
            if (view->has_data("wm-actions-showdesktop"))
            {
                view->erase_data("wm-actions-showdesktop");
                view->minimize_request(false);
            }
        }

        showdesktop_active = false;
    }

  public:
    void init() override
    {
        always_above = output->workspace->create_sublayer(
            wf::LAYER_WORKSPACE, wf::SUBLAYER_DOCKED_ABOVE);
        output->add_activator(toggle_showdesktop, &on_toggle_showdesktop);
        output->add_activator(minimize, &on_minimize);
        output->add_activator(toggle_maximize, &on_toggle_maximize);
        output->add_activator(toggle_above, &on_toggle_above);
        output->add_activator(toggle_fullscreen, &on_toggle_fullscreen);
        output->add_activator(toggle_sticky, &on_toggle_sticky);
        output->connect_signal("wm-actions-toggle-above", &on_toggle_above_signal);
        output->connect_signal("view-minimized", &on_view_minimized);
        wf::get_core().connect_signal("view-moved-to-output",
            &on_view_output_changed);
    }

    void fini() override
    {
        auto always_on_top_views =
            output->workspace->get_views_in_sublayer(always_above);

        for (auto view : always_on_top_views)
        {
            view->erase_data("wm-actions-above");
        }

        output->workspace->destroy_sublayer(always_above);
        output->rem_binding(&on_toggle_showdesktop);
        output->rem_binding(&on_minimize);
        output->rem_binding(&on_toggle_maximize);
        output->rem_binding(&on_toggle_above);
        output->rem_binding(&on_toggle_fullscreen);
        output->rem_binding(&on_toggle_sticky);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_wm_actions_t);
<|endoftext|>


<commit_before>#ifndef CWRAPPER_HPP_INCLUDED
#define CWRAPPER_HPP_INCLUDED

enum class CWrapperType
{
    Implicit,
    Explicit,
    Get,
};

template<
    typename H,
    typename F,
    CWrapperType TY,
    bool C,
    typename E>
class __CWrapperHelper__
{

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ArrowHandler
{ };

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, false>
{
    PTR_T* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* operator->()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename BASE,
    CWrapperType TYPE,
    bool CONSTSAFE>
struct ConversionHandler : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{ };

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Implicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Explicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    explicit operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Get, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    HANDLE_T get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Implicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Explicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    explicit operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    explicit operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Get, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* get()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T>
class CWrapperBase
    : public ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>;
protected:
    HANDLE_T ptr;

public:

    explicit CWrapperBase(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(ptr == nullptr)
            throw EXCEPTION_T{};
    }

    CWrapperBase(CWrapperBase const& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperBase(CWrapperBase& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    template<typename... ARGS>
    explicit CWrapperBase(ARGS&&... args) :
        CWrapperBase{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperBase(CWrapperBase&& old) :
        CWrapperBase{old.ptr}
    {
        old.ptr = nullptr;
    }

    CWrapperBase& operator=(CWrapperBase&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = nullptr;
        }
        return *this;
    }

    ~CWrapperBase()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    CWrapperBase& operator=(CWrapperBase const& other)
    {
        if(this != &other)
        {
            HANDLE_T new_ptr = FUNCTIONS::copy_func(other.ptr);
            if(new_ptr == nullptr)
                throw EXCEPTION_T{};

            FUNCTIONS::dtor_func(ptr);
            ptr = new_ptr;
        }
        return *this;
    }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T>
class CWrapperNonCopiable
    : public ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>;

protected:
    HANDLE_T ptr;

public:

    explicit CWrapperNonCopiable(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(ptr == nullptr)
            throw EXCEPTION_T{};
    }

    template<typename... ARGS>
    explicit CWrapperNonCopiable(ARGS&&... args) :
        CWrapperNonCopiable{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperNonCopiable(CWrapperNonCopiable&& old) :
        CWrapperNonCopiable{old.ptr}
    {
        old.ptr = nullptr;
    }

    CWrapperNonCopiable& operator=(CWrapperNonCopiable&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = nullptr;
        }
        return *this;
    }

    ~CWrapperNonCopiable()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperNonCopiable(CWrapperNonCopiable& other) = delete;
    CWrapperNonCopiable(CWrapperNonCopiable const& other) = delete;
    CWrapperNonCopiable& operator=(CWrapperNonCopiable const& other) = delete;
};

template<typename T1, typename T2>
struct EQ
{
    static constexpr bool value = false;
};

template<typename T>
struct EQ<T, T>
{
    static constexpr bool value = true;
};

template<bool condition, typename TRUE_TYPE, typename FALSE_TYPE>
struct COND
{
    using type = TRUE_TYPE;
};

template<typename TRUE_TYPE, typename FALSE_TYPE>
struct COND<false, TRUE_TYPE, FALSE_TYPE>
{
    using type = FALSE_TYPE;
};

template <typename FUNCTIONS>
static void has_copy_helper(...) { }

template <typename FUNCTIONS>
static int has_copy_helper(int, decltype(FUNCTIONS::copy_func)* func = nullptr) { return 0; }

public:

    using type = typename COND< EQ<decltype(has_copy_helper<F>(0)), int>::value,
        CWrapperBase<H, F, TY, C, E>,
        CWrapperNonCopiable<H, F, TY, C, E>>::type;
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE = CWrapperType::Get,
    bool CONSTSAFE = true,
    typename EXCEPTION_T = std::bad_alloc>
using CWrapper = typename __CWrapperHelper__<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>::type;

#endif // CWRAPPER_HPP_INCLUDED
<commit_msg>Static member detection and invalid value improved<commit_after>#ifndef CWRAPPER_HPP_INCLUDED
#define CWRAPPER_HPP_INCLUDED

#define HAS_STATIC_MEMBER_DETECTOR(member)                                  \
template<typename T>                                                        \
class HAS_STATIC_MEMBER_DETECTOR_CLASS_ ## member                           \
{                                                                           \
    struct two_ints_type { int two_ints_1, two_ints_2; };                   \
    template<typename U>                                                    \
    static two_ints_type has_func_helper(...) { }                           \
    template<typename U>                                                    \
    static int has_func_helper(int, decltype(U::member)* func = nullptr)    \
    { return 0; }                                                           \
public:                                                                     \
    static constexpr bool value =                                           \
        sizeof(decltype(has_func_helper<T>(0))) == sizeof(int);             \
}

#define HAS_STATIC_MEMBER(type, member)                                     \
    (HAS_STATIC_MEMBER_DETECTOR_CLASS_ ## member<type>::value)

enum class CWrapperType
{
    Implicit,
    Explicit,
    Get,
};

template<
    typename H,
    typename F,
    CWrapperType TY,
    bool C,
    typename E>
class __CWrapperHelper__
{

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ArrowHandler
{ };

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, false>
{
    PTR_T* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* operator->()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* operator->() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename BASE,
    CWrapperType TYPE,
    bool CONSTSAFE>
struct ConversionHandler : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{ };

template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Implicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Explicit, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    explicit operator HANDLE_T() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename HANDLE_T,
    typename BASE,
    bool CONSTSAFE>
struct ConversionHandler<HANDLE_T, BASE, CWrapperType::Get, CONSTSAFE>
    : public ArrowHandler<HANDLE_T, BASE, CONSTSAFE>
{
    HANDLE_T get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Implicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Explicit, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    explicit operator PTR_T*()
    {   return static_cast<BASE*>(this)->ptr; }
    explicit operator PTR_T const*() const
    {   return static_cast<BASE*>(this)->ptr; }
};
template<
    typename PTR_T,
    typename BASE>
struct ConversionHandler<PTR_T*, BASE, CWrapperType::Get, true>
    : public ArrowHandler<PTR_T*, BASE, true>
{
    PTR_T* get()
    {   return static_cast<BASE*>(this)->ptr; }
    PTR_T const* get() const
    {   return static_cast<BASE*>(this)->ptr; }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T>
class CWrapperBase
    : public ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperBase<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>;
protected:
    HANDLE_T ptr;

public:

    explicit CWrapperBase(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(!ptr)
            throw EXCEPTION_T{};
    }

    CWrapperBase(CWrapperBase const& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperBase(CWrapperBase& other) :
        CWrapperBase{FUNCTIONS::copy_func(other.ptr)}
    { }

    template<typename... ARGS>
    explicit CWrapperBase(ARGS&&... args) :
        CWrapperBase{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperBase(CWrapperBase&& old) :
        CWrapperBase{old.ptr}
    {
        old.ptr = 0;
    }

    CWrapperBase& operator=(CWrapperBase&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = 0;
        }
        return *this;
    }

    ~CWrapperBase()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    CWrapperBase& operator=(CWrapperBase const& other)
    {
        if(this != &other)
        {
            HANDLE_T new_ptr = FUNCTIONS::copy_func(other.ptr);
            if(!new_ptr)
                throw EXCEPTION_T{};

            FUNCTIONS::dtor_func(ptr);
            ptr = new_ptr;
        }
        return *this;
    }
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE,
    bool CONSTSAFE,
    typename EXCEPTION_T>
class CWrapperNonCopiable
    : public ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>
{
    friend class ConversionHandler<
        HANDLE_T,
        CWrapperNonCopiable<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>,
        TYPE,
        CONSTSAFE>;

protected:
    HANDLE_T ptr;

public:

    explicit CWrapperNonCopiable(HANDLE_T ptr) :
        ptr{ptr}
    {
        if(!ptr)
            throw EXCEPTION_T{};
    }

    template<typename... ARGS>
    explicit CWrapperNonCopiable(ARGS&&... args) :
        CWrapperNonCopiable{FUNCTIONS::ctor_func(std::forward<ARGS>(args)...)}
    { }

    CWrapperNonCopiable(CWrapperNonCopiable&& old) :
        CWrapperNonCopiable{old.ptr}
    {
        old.ptr = 0;
    }

    CWrapperNonCopiable& operator=(CWrapperNonCopiable&& old)
    {
        if(this != &old)
        {
            FUNCTIONS::dtor_func(ptr);
            ptr = old.ptr;
            old.ptr = 0;
        }
        return *this;
    }

    ~CWrapperNonCopiable()
    {
        FUNCTIONS::dtor_func(ptr);
    }

    // This one is needed to prevent variadic ctor to be called
    // when you want to copy a non-const object.
    CWrapperNonCopiable(CWrapperNonCopiable& other) = delete;
    CWrapperNonCopiable(CWrapperNonCopiable const& other) = delete;
    CWrapperNonCopiable& operator=(CWrapperNonCopiable const& other) = delete;
};

template<bool condition, typename TRUE_TYPE, typename FALSE_TYPE>
struct COND
{
    using type = TRUE_TYPE;
};

template<typename TRUE_TYPE, typename FALSE_TYPE>
struct COND<false, TRUE_TYPE, FALSE_TYPE>
{
    using type = FALSE_TYPE;
};

HAS_STATIC_MEMBER_DETECTOR(copy_func);

public:

    using type = typename COND< HAS_STATIC_MEMBER(F, copy_func),
        CWrapperBase<H, F, TY, C, E>,
        CWrapperNonCopiable<H, F, TY, C, E>>::type;
};

template<
    typename HANDLE_T,
    typename FUNCTIONS,
    CWrapperType TYPE = CWrapperType::Get,
    bool CONSTSAFE = true,
    typename EXCEPTION_T = std::bad_alloc>
using CWrapper = typename __CWrapperHelper__<HANDLE_T, FUNCTIONS, TYPE, CONSTSAFE, EXCEPTION_T>::type;

#endif // CWRAPPER_HPP_INCLUDED
<|endoftext|>


<commit_before>#include "cache_set_srrip.h"
#include "simulator.h"
#include "config.hpp"
#include "log.h"

// S-RRIP: Static Re-reference Interval Prediction policy

CacheSetSRRIP::CacheSetSRRIP(
      String cfgname, core_id_t core_id,
      CacheBase::cache_t cache_type,
      UInt32 associativity, UInt32 blocksize, CacheSetInfoLRU* set_info, UInt8 num_attempts)
   : CacheSet(cache_type, associativity, blocksize)
   , m_rrip_numbits(Sim()->getCfg()->getIntArray(cfgname + "/srrip/bits", core_id))
   , m_rrip_max((1 << m_rrip_numbits) - 1)
   , m_rrip_insert(m_rrip_max - 1)
   , m_num_attempts(num_attempts)
   , m_replacement_pointer(0)
   , m_set_info(set_info)
{
   m_rrip_bits = new UInt8[m_associativity];
   for (UInt32 i = 0; i < m_associativity; i++)
      m_rrip_bits[i] = m_rrip_insert;
}

CacheSetSRRIP::~CacheSetSRRIP()
{
   delete [] m_rrip_bits;
}

UInt32
CacheSetSRRIP::getReplacementIndex(CacheCntlr *cntlr)
{
   for (UInt32 i = 0; i < m_associativity; i++)
   {
      if (!m_cache_block_info_array[i]->isValid())
      {
         // If there is an invalid line(s) in the set, regardless of the LRU bits of other lines, we choose the first invalid line to replace
         // Prepare way for a new line: set prediction to 'long'
         m_rrip_bits[i] = m_rrip_insert;
         return i;
      }
   }

   UInt8 attempt = 0;

   for(UInt32 j = 0; j <= m_rrip_max; ++j)
   {
      for (UInt32 i = 0; i < m_associativity; i++)
      {
         if (m_rrip_bits[m_replacement_pointer] == m_rrip_max)
         {
            // We choose the first non-touched line as the victim (note that we start searching from the replacement pointer position)
            UInt8 index = m_replacement_pointer;

            bool qbs_reject = false;
            if (attempt < m_num_attempts - 1)
            {
               LOG_ASSERT_ERROR(cntlr != NULL, "CacheCntlr == NULL, QBS can only be used when cntlr is passed in");
               qbs_reject = cntlr->isInLowerLevelCache(m_cache_block_info_array[index]);
            }

            if (qbs_reject)
            {
               // Block is contained in lower-level cache, and we have more tries remaining.
               // Move this block to MRU and try again
               m_rrip_bits[index] = 0;
               cntlr->incrementQBSLookupCost();
               ++attempt;
               continue;
            }

            m_replacement_pointer = (m_replacement_pointer + 1) % m_associativity;
            // Prepare way for a new line: set prediction to 'long'
            m_rrip_bits[index] = m_rrip_insert;

            m_set_info->incrementAttempt(attempt);

            LOG_ASSERT_ERROR(isValidReplacement(index), "SRRIP selected an invalid replacement candidate" );
            return index;
         }

         m_replacement_pointer = (m_replacement_pointer + 1) % m_associativity;
      }

      // Increment all RRIP counters until one hits RRIP_MAX
      for (UInt32 i = 0; i < m_associativity; i++)
      {
         m_rrip_bits[i]++;
      }
   }

   LOG_PRINT_ERROR("Error finding replacement index");
}

void
CacheSetSRRIP::updateReplacementIndex(UInt32 accessed_index)
{
   m_set_info->increment(m_rrip_bits[accessed_index]);

   if (m_rrip_bits[accessed_index] > 0)
      m_rrip_bits[accessed_index]--;
}
<commit_msg>[cache] fixed bug where shared_upgrading blocks could cause srrip_bits > srrip_max<commit_after>#include "cache_set_srrip.h"
#include "simulator.h"
#include "config.hpp"
#include "log.h"

// S-RRIP: Static Re-reference Interval Prediction policy

CacheSetSRRIP::CacheSetSRRIP(
      String cfgname, core_id_t core_id,
      CacheBase::cache_t cache_type,
      UInt32 associativity, UInt32 blocksize, CacheSetInfoLRU* set_info, UInt8 num_attempts)
   : CacheSet(cache_type, associativity, blocksize)
   , m_rrip_numbits(Sim()->getCfg()->getIntArray(cfgname + "/srrip/bits", core_id))
   , m_rrip_max((1 << m_rrip_numbits) - 1)
   , m_rrip_insert(m_rrip_max - 1)
   , m_num_attempts(num_attempts)
   , m_replacement_pointer(0)
   , m_set_info(set_info)
{
   m_rrip_bits = new UInt8[m_associativity];
   for (UInt32 i = 0; i < m_associativity; i++)
      m_rrip_bits[i] = m_rrip_insert;
}

CacheSetSRRIP::~CacheSetSRRIP()
{
   delete [] m_rrip_bits;
}

UInt32
CacheSetSRRIP::getReplacementIndex(CacheCntlr *cntlr)
{
   for (UInt32 i = 0; i < m_associativity; i++)
   {
      if (!m_cache_block_info_array[i]->isValid())
      {
         // If there is an invalid line(s) in the set, regardless of the LRU bits of other lines, we choose the first invalid line to replace
         // Prepare way for a new line: set prediction to 'long'
         m_rrip_bits[i] = m_rrip_insert;
         return i;
      }
   }

   UInt8 attempt = 0;

   for(UInt32 j = 0; j <= m_rrip_max; ++j)
   {
      for (UInt32 i = 0; i < m_associativity; i++)
      {
         if (m_rrip_bits[m_replacement_pointer] >= m_rrip_max)
         {
            // We choose the first non-touched line as the victim (note that we start searching from the replacement pointer position)
            UInt8 index = m_replacement_pointer;

            bool qbs_reject = false;
            if (attempt < m_num_attempts - 1)
            {
               LOG_ASSERT_ERROR(cntlr != NULL, "CacheCntlr == NULL, QBS can only be used when cntlr is passed in");
               qbs_reject = cntlr->isInLowerLevelCache(m_cache_block_info_array[index]);
            }

            if (qbs_reject)
            {
               // Block is contained in lower-level cache, and we have more tries remaining.
               // Move this block to MRU and try again
               m_rrip_bits[index] = 0;
               cntlr->incrementQBSLookupCost();
               ++attempt;
               continue;
            }

            m_replacement_pointer = (m_replacement_pointer + 1) % m_associativity;
            // Prepare way for a new line: set prediction to 'long'
            m_rrip_bits[index] = m_rrip_insert;

            m_set_info->incrementAttempt(attempt);

            LOG_ASSERT_ERROR(isValidReplacement(index), "SRRIP selected an invalid replacement candidate" );
            return index;
         }

         m_replacement_pointer = (m_replacement_pointer + 1) % m_associativity;
      }

      // Increment all RRIP counters until one hits RRIP_MAX
      for (UInt32 i = 0; i < m_associativity; i++)
      {
         if (m_rrip_bits[i] < m_rrip_max)
         {
            m_rrip_bits[i]++;
         }
      }
   }

   LOG_PRINT_ERROR("Error finding replacement index");
}

void
CacheSetSRRIP::updateReplacementIndex(UInt32 accessed_index)
{
   m_set_info->increment(m_rrip_bits[accessed_index]);

   if (m_rrip_bits[accessed_index] > 0)
      m_rrip_bits[accessed_index]--;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_BASE_HH
#define DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_BASE_HH

#include <type_traits>

#include <dune/common/typetraits.hh>
#include <dune/common/dynvector.hh>
#include <dune/common/version.hh>

#include <dune/stuff/common/disable_warnings.hh>
#if DUNE_VERSION_NEWER(DUNE_COMMON, 3, 9) // EXADUNE
#include <dune/geometry/referenceelements.hh>
#else
#include <dune/geometry/genericreferenceelements.hh>
#endif
#include <dune/common/typetraits.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/stuff/common/exceptions.hh>

#include "../interface.hh"

namespace Dune {
namespace GDT {
namespace Spaces {

// forward, to allow for specialization
template <class ImpTraits, int domainDim, class RangeFieldImp, int rangeDim, int rangeDimCols = 1>
class ContinuousLagrangeBase
{
  static_assert(AlwaysFalse<ImpTraits>::value, "Untested for these dimensions!");
};

template <class ImpTraits, int domainDim, class RangeFieldImp, int rangeDim>
class ContinuousLagrangeBase<ImpTraits, domainDim, RangeFieldImp, rangeDim, 1> : public SpaceInterface<ImpTraits>
{
  typedef SpaceInterface<ImpTraits> BaseType;
  typedef ContinuousLagrangeBase<ImpTraits, domainDim, RangeFieldImp, rangeDim, 1> ThisType;

  static constexpr RangeFieldImp compare_tolerance_ = 1e-13;

public:
  typedef ImpTraits Traits;

  using BaseType::polOrder;

  using typename BaseType::DomainFieldType;
  using BaseType::dimDomain;
  using typename BaseType::DomainType;

  typedef typename Traits::RangeFieldType RangeFieldType;
  using BaseType::dimRange;
  using BaseType::dimRangeCols;

  using typename BaseType::EntityType;
  using typename BaseType::IntersectionType;
  using typename BaseType::BoundaryInfoType;
  using typename BaseType::PatternType;

  virtual ~ContinuousLagrangeBase()
  {
  }

  using BaseType::compute_pattern;

  template <class G, class S>
  PatternType compute_pattern(const GridView<G>& local_grid_view, const SpaceInterface<S>& ansatz_space) const
  {
    return BaseType::compute_volume_pattern(local_grid_view, ansatz_space);
  }

  virtual std::vector<DomainType> lagrange_points(const EntityType& entity) const
  {
    // check
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    assert(this->grid_view()->indexSet().contains(entity));
    // get the basis and reference element
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector<RangeType> tmp_basis_values(RangeType(0), basis.size());
    const auto& reference_element = ReferenceElements<DomainFieldType, dimDomain>::general(entity.type());
    const int num_vertices = reference_element.size(dimDomain);
    assert(num_vertices >= 0);
    assert(size_t(num_vertices) == basis.size() && "This should not happen with polOrder 1!");
    // prepare return vector
    std::vector<DomainType> local_vertices(num_vertices, DomainType(0));
    if (tmp_basis_values.size() < basis.size())
      tmp_basis_values.resize(basis.size());
    // loop over all vertices
    for (int ii = 0; ii < num_vertices; ++ii) {
      // get the local coordinate of the iith vertex
      const auto local_vertex = reference_element.position(ii, dimDomain);
      // evaluate the basefunctionset
      basis.evaluate(local_vertex, tmp_basis_values);
      // find the basis function that evaluates to one here (has to be only one!)
      size_t ones     = 0;
      size_t zeros    = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs((tmp_basis_values)[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          local_vertices[jj] = local_vertex;
          ++ones;
        } else if (std::abs((tmp_basis_values)[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return local_vertices;
  } // ... lagrange_points(...)

  virtual std::set<size_t> local_dirichlet_DoFs(const EntityType& entity, const BoundaryInfoType& boundaryInfo) const
  {
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    // check
    assert(this->grid_view()->indexSet().contains(entity));
    // prepare
    std::set<size_t> localDirichletDofs;
    std::vector<DomainType> dirichlet_vertices;
    // get all dirichlet vertices of this entity, therefore
    // * loop over all intersections
    const auto intersection_it_end = this->grid_view()->iend(entity);
    for (auto intersection_it = this->grid_view()->ibegin(entity); intersection_it != intersection_it_end;
         ++intersection_it) {
      // only work on dirichlet ones
      const auto& intersection = *intersection_it;
      // actual dirichlet intersections + process boundaries for parallel runs
      if (boundaryInfo.dirichlet(intersection) || (!intersection.neighbor() && !intersection.boundary())) {
        // and get the vertices of the intersection
        const auto geometry = intersection.geometry();
        for (int cc = 0; cc < geometry.corners(); ++cc)
          dirichlet_vertices.emplace_back(entity.geometry().local(geometry.corner(cc)));
      } // only work on dirichlet ones
    } // loop over all intersections
    // find the corresponding basis functions
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector<RangeType> tmp_basis_values(RangeType(0), basis.size());
    for (size_t cc = 0; cc < dirichlet_vertices.size(); ++cc) {
      // find the basis function that evaluates to one here (has to be only one!)
      basis.evaluate(dirichlet_vertices[cc], tmp_basis_values);
      size_t ones     = 0;
      size_t zeros    = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs(tmp_basis_values[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          localDirichletDofs.insert(jj);
          ++ones;
        } else if (std::abs(tmp_basis_values[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return localDirichletDofs;
  } // ... local_dirichlet_DoFs(...)

  using BaseType::local_constraints;

  template <class S, class ConstraintsType>
  void local_constraints(const SpaceInterface<S>& /*other*/, const EntityType& /*entity*/,
                         ConstraintsType& /*ret*/) const
  {
    static_assert(AlwaysFalse<S>::value, "Not implemented for these constraints!");
  }

  template <class S>
  void local_constraints(const SpaceInterface<S>& other, const EntityType& entity,
                         Constraints::Dirichlet<IntersectionType, RangeFieldType>& ret) const
  {
    // check
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    assert(this->grid_view()->indexSet().contains(entity));
    const std::set<size_t> localDirichletDofs = this->local_dirichlet_DoFs(entity, ret.boundary_info());
    const size_t numRows                      = localDirichletDofs.size();
    Dune::DynamicVector<size_t> tmpMappedRows;
    Dune::DynamicVector<size_t> tmpMappedCols;
    if (numRows > 0) {
      const size_t numCols = this->mapper().numDofs(entity);
      ret.set_size(numRows, numCols);
      this->mapper().globalIndices(entity, tmpMappedRows);
      other.mapper().globalIndices(entity, tmpMappedCols);
      size_t localRow = 0;
      for (const size_t& localDirichletDofIndex : localDirichletDofs) {
        ret.global_row(localRow) = tmpMappedRows[localDirichletDofIndex];
        for (size_t jj = 0; jj < ret.cols(); ++jj) {
          ret.global_col(jj) = tmpMappedCols[jj];
          if (tmpMappedCols[jj] == tmpMappedRows[localDirichletDofIndex])
            ret.value(localRow, jj) = ret.set_row() ? 1 : 0;
          else
            ret.value(localRow, jj) = 0;
        }
        ++localRow;
      }
    } else {
      ret.set_size(0, 0);
    }
  } // ... local_constraints(..., Constraints::Dirichlet< ... > ...)

}; // class ContinuousLagrangeBase

} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_BASE_HH
<commit_msg>fixes 7cfe517eacafd5d366959d9f674cd8e56d951eac<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_BASE_HH
#define DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_BASE_HH

#include <type_traits>

#include <dune/common/typetraits.hh>
#include <dune/common/dynvector.hh>
#include <dune/common/version.hh>

#include <dune/stuff/common/disable_warnings.hh>
#if DUNE_VERSION_NEWER(DUNE_COMMON, 3, 9) // EXADUNE
#include <dune/geometry/referenceelements.hh>
#else
#include <dune/geometry/genericreferenceelements.hh>
#endif
#include <dune/common/typetraits.hh>
#include <dune/stuff/common/reenable_warnings.hh>

#include <dune/stuff/common/exceptions.hh>

#include "../interface.hh"

namespace Dune {
namespace GDT {
namespace Spaces {

// forward, to allow for specialization
template <class ImpTraits, int domainDim, class RangeFieldImp, int rangeDim, int rangeDimCols = 1>
class ContinuousLagrangeBase
{
  static_assert(AlwaysFalse<ImpTraits>::value, "Untested for these dimensions!");
};

template <class ImpTraits, int domainDim, class RangeFieldImp, int rangeDim>
class ContinuousLagrangeBase<ImpTraits, domainDim, RangeFieldImp, rangeDim, 1> : public SpaceInterface<ImpTraits>
{
  typedef SpaceInterface<ImpTraits> BaseType;
  typedef ContinuousLagrangeBase<ImpTraits, domainDim, RangeFieldImp, rangeDim, 1> ThisType;

  static constexpr RangeFieldImp compare_tolerance_ = 1e-13;

public:
  typedef ImpTraits Traits;

  using BaseType::polOrder;

  using typename BaseType::DomainFieldType;
  using BaseType::dimDomain;
  using typename BaseType::DomainType;

  typedef typename Traits::RangeFieldType RangeFieldType;
  using BaseType::dimRange;
  using BaseType::dimRangeCols;

  using typename BaseType::EntityType;
  using typename BaseType::IntersectionType;
  using typename BaseType::BoundaryInfoType;
  using typename BaseType::PatternType;

  virtual ~ContinuousLagrangeBase()
  {
  }

  using BaseType::compute_pattern;

  template <class G, class S>
  PatternType compute_pattern(const GridView<G>& local_grid_view, const SpaceInterface<S>& ansatz_space) const
  {
    return BaseType::compute_volume_pattern(local_grid_view, ansatz_space);
  }

  virtual std::vector<DomainType> lagrange_points(const EntityType& entity) const
  {
    // check
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    assert(this->grid_view()->indexSet().contains(entity));
    // get the basis and reference element
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector<RangeType> tmp_basis_values(basis.size(), RangeType(0));
    const auto& reference_element = ReferenceElements<DomainFieldType, dimDomain>::general(entity.type());
    const int num_vertices = reference_element.size(dimDomain);
    assert(num_vertices >= 0);
    assert(size_t(num_vertices) == basis.size() && "This should not happen with polOrder 1!");
    // prepare return vector
    std::vector<DomainType> local_vertices(num_vertices, DomainType(0));
    // loop over all vertices
    for (int ii = 0; ii < num_vertices; ++ii) {
      // get the local coordinate of the iith vertex
      const auto local_vertex = reference_element.position(ii, dimDomain);
      // evaluate the basefunctionset
      basis.evaluate(local_vertex, tmp_basis_values);
      // find the basis function that evaluates to one here (has to be only one!)
      size_t ones     = 0;
      size_t zeros    = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs((tmp_basis_values)[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          local_vertices[jj] = local_vertex;
          ++ones;
        } else if (std::abs((tmp_basis_values)[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return local_vertices;
  } // ... lagrange_points(...)

  virtual std::set<size_t> local_dirichlet_DoFs(const EntityType& entity, const BoundaryInfoType& boundaryInfo) const
  {
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    // check
    assert(this->grid_view()->indexSet().contains(entity));
    // prepare
    std::set<size_t> localDirichletDofs;
    std::vector<DomainType> dirichlet_vertices;
    // get all dirichlet vertices of this entity, therefore
    // * loop over all intersections
    const auto intersection_it_end = this->grid_view()->iend(entity);
    for (auto intersection_it = this->grid_view()->ibegin(entity); intersection_it != intersection_it_end;
         ++intersection_it) {
      // only work on dirichlet ones
      const auto& intersection = *intersection_it;
      // actual dirichlet intersections + process boundaries for parallel runs
      if (boundaryInfo.dirichlet(intersection) || (!intersection.neighbor() && !intersection.boundary())) {
        // and get the vertices of the intersection
        const auto geometry = intersection.geometry();
        for (int cc = 0; cc < geometry.corners(); ++cc)
          dirichlet_vertices.emplace_back(entity.geometry().local(geometry.corner(cc)));
      } // only work on dirichlet ones
    } // loop over all intersections
    // find the corresponding basis functions
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector<RangeType> tmp_basis_values(basis.size(), RangeType(0));
    for (size_t cc = 0; cc < dirichlet_vertices.size(); ++cc) {
      // find the basis function that evaluates to one here (has to be only one!)
      basis.evaluate(dirichlet_vertices[cc], tmp_basis_values);
      size_t ones     = 0;
      size_t zeros    = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs(tmp_basis_values[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          localDirichletDofs.insert(jj);
          ++ones;
        } else if (std::abs(tmp_basis_values[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return localDirichletDofs;
  } // ... local_dirichlet_DoFs(...)

  using BaseType::local_constraints;

  template <class S, class ConstraintsType>
  void local_constraints(const SpaceInterface<S>& /*other*/, const EntityType& /*entity*/,
                         ConstraintsType& /*ret*/) const
  {
    static_assert(AlwaysFalse<S>::value, "Not implemented for these constraints!");
  }

  template <class S>
  void local_constraints(const SpaceInterface<S>& other, const EntityType& entity,
                         Constraints::Dirichlet<IntersectionType, RangeFieldType>& ret) const
  {
    // check
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    assert(this->grid_view()->indexSet().contains(entity));
    const std::set<size_t> localDirichletDofs = this->local_dirichlet_DoFs(entity, ret.boundary_info());
    const size_t numRows                      = localDirichletDofs.size();
    Dune::DynamicVector<size_t> tmpMappedRows;
    Dune::DynamicVector<size_t> tmpMappedCols;
    if (numRows > 0) {
      const size_t numCols = this->mapper().numDofs(entity);
      ret.set_size(numRows, numCols);
      this->mapper().globalIndices(entity, tmpMappedRows);
      other.mapper().globalIndices(entity, tmpMappedCols);
      size_t localRow = 0;
      for (const size_t& localDirichletDofIndex : localDirichletDofs) {
        ret.global_row(localRow) = tmpMappedRows[localDirichletDofIndex];
        for (size_t jj = 0; jj < ret.cols(); ++jj) {
          ret.global_col(jj) = tmpMappedCols[jj];
          if (tmpMappedCols[jj] == tmpMappedRows[localDirichletDofIndex])
            ret.value(localRow, jj) = ret.set_row() ? 1 : 0;
          else
            ret.value(localRow, jj) = 0;
        }
        ++localRow;
      }
    } else {
      ret.set_size(0, 0);
    }
  } // ... local_constraints(..., Constraints::Dirichlet< ... > ...)

}; // class ContinuousLagrangeBase

} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CONTINUOUSLAGRANGE_BASE_HH
<|endoftext|>


<commit_before><commit_msg>11286 - Conformity<commit_after><|endoftext|>


<commit_before>#include "TextureMaterial.h"

namespace libshape
{

TextureMaterial::TextureMaterial(const std::vector<d2d::Vector>& vertices, d2d::ImageSymbol* image)
{
	image->Retain();
	m_image = image;

	BuildBegin(vertices);
	BuildEnd();
}

TextureMaterial::~TextureMaterial()
{
	m_image->Release();
}

Json::Value TextureMaterial::Store(const std::string& dirpath) const
{
	Json::Value val;
	val["type"] = "texture";
	val["texture path"] = d2d::FilenameTools::getRelativePath(dirpath, m_image->getFilepath()).ToStdString();
	return val;
}

void TextureMaterial::Translate(const d2d::Vector& offset)
{
	Material::Translate(offset);
	for (int i = 0, n = m_tris_texcoord.size(); i < n; ++i) {
		m_tris_texcoord[i] += offset;
	}
}

void TextureMaterial::Draw(const d2d::Matrix& mt) const
{
	if (m_tris.empty()) {
		return;
	}
	assert(m_tris.size() == m_tris_texcoord.size()
		&& m_tris.size() % 3 == 0);

	d2d::ShaderMgr* shader = d2d::ShaderMgr::Instance();
	shader->sprite();
	for (int i = 0, n = m_tris.size(); i < n; i += 3) {
		d2d::Vector vertices[4], texcoords[4];
		for (int j = 0; j < 3; ++j) {
			vertices[j] = d2d::Math::transVector(m_tris[i+j], mt);
			texcoords[j] = m_tris_texcoord[i+j];
		}
		vertices[3] = vertices[2];
		texcoords[3] = texcoords[2];
		shader->Draw(vertices, texcoords, m_image->getTextureID());
	}
}

void TextureMaterial::ReloadTexture()
{
	m_image->reloadTexture();
}

void TextureMaterial::BuildEnd()
{
	std::ofstream fout("debug_poly.txt", std::ios::app);

	fout << "TextureMaterial::BuildEnd 0 \n";

	m_tris.clear();
	m_tris_texcoord.clear();

	std::vector<d2d::Vector> outline;
	d2d::Math::removeDuplicatePoints(m_outline, outline);

	d2d::Rect r = GetBoundingRegion(outline);

	fout << "TextureMaterial::BuildEnd 1 \n";

	std::vector<d2d::Vector> segments;
	GetTexBoundarySegments(r, segments);
	if (!m_segments.empty()) {
		copy(m_segments.begin(), m_segments.end(), back_inserter(segments));
	}

	fout << "TextureMaterial::BuildEnd 2 \n";

	d2d::Triangulation::lines(outline, segments, m_tris);

	fout << "TextureMaterial::BuildEnd 3 \n";

	CalTexcoords(r);

	fout << "TextureMaterial::BuildEnd 4 \n";

	fout.close();
}

d2d::Rect TextureMaterial::GetBoundingRegion(const std::vector<d2d::Vector>& bounding) const
{
	d2d::Rect r;
	for (int i = 0, n = bounding.size(); i < n; ++i) {
		r.combine(bounding[i]);
	}
	return r;
}

void TextureMaterial::GetTexBoundarySegments(const d2d::Rect& rect, std::vector<d2d::Vector>& segments)
{
	int width = m_image->getSize().xLength(),
		height = m_image->getSize().yLength();
	for (float x = rect.xMin; x < rect.xMax; x += width)
	{
		segments.push_back(d2d::Vector(x, rect.yMin - 1));
		segments.push_back(d2d::Vector(x, rect.yMax + 1));
	}
	for (float y = rect.yMin; y < rect.yMax; y += height)
	{
		segments.push_back(d2d::Vector(rect.xMin - 1, y));
		segments.push_back(d2d::Vector(rect.xMax + 1, y));
	}
}

void TextureMaterial::CalTexcoords(const d2d::Rect& rect)
{
	int width = m_image->getSize().xLength(),
		height = m_image->getSize().yLength();
	int index = 0;
	for (size_t i = 0, n = m_tris.size() / 3; i < n; ++i)
	{
		float cx = 0, cy = 0;
		for (size_t j = 0; j < 3; ++j)
		{
			cx += m_tris[index + j].x;
			cy += m_tris[index + j].y;
		}
		cx /= 3;
		cy /= 3;

		int ix = (cx - rect.xMin) / width,
			iy = (cy - rect.yMin) / height;
		d2d::Vector base;
		base.x = rect.xMin + width * ix;
		base.y = rect.yMin + height * iy;

		for (size_t j = 0; j < 3; ++j)
		{
			float tx = (m_tris[index + j].x - base.x) / width,
				  ty = (m_tris[index + j].y - base.y) / height;
			m_tris_texcoord.push_back(d2d::Vector(tx, ty));
		}

		index +=  3;
	}
}

}<commit_msg>[CHANGED] log for TextureMaterial::BuildEnd<commit_after>#include "TextureMaterial.h"

namespace libshape
{

TextureMaterial::TextureMaterial(const std::vector<d2d::Vector>& vertices, d2d::ImageSymbol* image)
{
	image->Retain();
	m_image = image;

	BuildBegin(vertices);
	BuildEnd();
}

TextureMaterial::~TextureMaterial()
{
	m_image->Release();
}

Json::Value TextureMaterial::Store(const std::string& dirpath) const
{
	Json::Value val;
	val["type"] = "texture";
	val["texture path"] = d2d::FilenameTools::getRelativePath(dirpath, m_image->getFilepath()).ToStdString();
	return val;
}

void TextureMaterial::Translate(const d2d::Vector& offset)
{
	Material::Translate(offset);
	for (int i = 0, n = m_tris_texcoord.size(); i < n; ++i) {
		m_tris_texcoord[i] += offset;
	}
}

void TextureMaterial::Draw(const d2d::Matrix& mt) const
{
	if (m_tris.empty()) {
		return;
	}
	assert(m_tris.size() == m_tris_texcoord.size()
		&& m_tris.size() % 3 == 0);

	d2d::ShaderMgr* shader = d2d::ShaderMgr::Instance();
	shader->sprite();
	for (int i = 0, n = m_tris.size(); i < n; i += 3) {
		d2d::Vector vertices[4], texcoords[4];
		for (int j = 0; j < 3; ++j) {
			vertices[j] = d2d::Math::transVector(m_tris[i+j], mt);
			texcoords[j] = m_tris_texcoord[i+j];
		}
		vertices[3] = vertices[2];
		texcoords[3] = texcoords[2];
		shader->Draw(vertices, texcoords, m_image->getTextureID());
	}
}

void TextureMaterial::ReloadTexture()
{
	m_image->reloadTexture();
}

void TextureMaterial::BuildEnd()
{
	m_tris.clear();
	m_tris_texcoord.clear();

	std::vector<d2d::Vector> outline;
	d2d::Math::removeDuplicatePoints(m_outline, outline);

	d2d::Rect r = GetBoundingRegion(outline);

	std::vector<d2d::Vector> segments;
	GetTexBoundarySegments(r, segments);
	if (!m_segments.empty()) {
		copy(m_segments.begin(), m_segments.end(), back_inserter(segments));
	}

	Json::Value value;
	d2d::JsonTools::store(outline, value["outline"]);
	d2d::JsonTools::store(segments, value["segments"]);

	Json::StyledStreamWriter writer;
	std::locale::global(std::locale(""));
	std::ofstream fout("debug_poly.json");
	std::locale::global(std::locale("C"));
	writer.write(fout, value);
	fout.close();

	d2d::Triangulation::lines(outline, segments, m_tris);

	CalTexcoords(r);

	fout.close();
}

d2d::Rect TextureMaterial::GetBoundingRegion(const std::vector<d2d::Vector>& bounding) const
{
	d2d::Rect r;
	for (int i = 0, n = bounding.size(); i < n; ++i) {
		r.combine(bounding[i]);
	}
	return r;
}

void TextureMaterial::GetTexBoundarySegments(const d2d::Rect& rect, std::vector<d2d::Vector>& segments)
{
	int width = m_image->getSize().xLength(),
		height = m_image->getSize().yLength();
	for (float x = rect.xMin; x < rect.xMax; x += width)
	{
		segments.push_back(d2d::Vector(x, rect.yMin - 1));
		segments.push_back(d2d::Vector(x, rect.yMax + 1));
	}
	for (float y = rect.yMin; y < rect.yMax; y += height)
	{
		segments.push_back(d2d::Vector(rect.xMin - 1, y));
		segments.push_back(d2d::Vector(rect.xMax + 1, y));
	}
}

void TextureMaterial::CalTexcoords(const d2d::Rect& rect)
{
	int width = m_image->getSize().xLength(),
		height = m_image->getSize().yLength();
	int index = 0;
	for (size_t i = 0, n = m_tris.size() / 3; i < n; ++i)
	{
		float cx = 0, cy = 0;
		for (size_t j = 0; j < 3; ++j)
		{
			cx += m_tris[index + j].x;
			cy += m_tris[index + j].y;
		}
		cx /= 3;
		cy /= 3;

		int ix = (cx - rect.xMin) / width,
			iy = (cy - rect.yMin) / height;
		d2d::Vector base;
		base.x = rect.xMin + width * ix;
		base.y = rect.yMin + height * iy;

		for (size_t j = 0; j < 3; ++j)
		{
			float tx = (m_tris[index + j].x - base.x) / width,
				  ty = (m_tris[index + j].y - base.y) / height;
			m_tris_texcoord.push_back(d2d::Vector(tx, ty));
		}

		index +=  3;
	}
}

}<|endoftext|>


<commit_before>#include "Runtime/Graphics/CPVSVisOctree.hpp"

namespace urde {

CPVSVisOctree CPVSVisOctree::MakePVSVisOctree(const u8* data) {
  CMemoryInStream r(data, 68);
  zeus::CAABox aabb = aabb.ReadBoundingBoxBig(r);
  u32 numObjects = r.readUint32Big();
  u32 numLights = r.readUint32Big();
  r.readUint32Big();
  return CPVSVisOctree(aabb, numObjects, numLights, data + r.position());
}

CPVSVisOctree::CPVSVisOctree(const zeus::CAABox& aabb, u32 numObjects, u32 numLights, const u8* c)
: x0_aabb(aabb), x18_numObjects(numObjects), x1c_numLights(numLights), x20_bufferFlag(c != nullptr), x24_octreeData(c) {
  x2c_searchAabb = x0_aabb;
  x20_bufferFlag = 0;
}

static const u32 NumChildTable[] = {0, 2, 2, 4, 2, 4, 4, 8};

u32 CPVSVisOctree::GetNumChildren(u8 byte) const { return NumChildTable[byte & 0x7]; }

u32 CPVSVisOctree::GetChildIndex(const u8*, const zeus::CVector3f&) const { return 0; }

s32 CPVSVisOctree::IterateSearch(u8 nodeData, const zeus::CVector3f& tp) const {
  if (!(nodeData & 0x7))
    return -1; // Leaf node

  zeus::CVector3f newMin = x2c_searchAabb.center();
  zeus::CVector3f newMax;
  bool highFlags[3];

  if (tp.x() > newMin.x()) {
    newMax.x() = x2c_searchAabb.max.x();
    highFlags[0] = true;
  } else {
    newMax.x() = float(newMin.x());
    newMin.x() = float(x2c_searchAabb.min.x());
    highFlags[0] = false;
  }

  if (tp.y() > newMin.y()) {
    newMax.y() = float(x2c_searchAabb.max.y());
    highFlags[1] = true;
  } else {
    newMax.y() = float(newMin.y());
    newMin.y() = float(x2c_searchAabb.min.y());
    highFlags[1] = false;
  }

  if (tp.z() > newMin.z()) {
    newMax.z() = float(x2c_searchAabb.max.z());
    highFlags[2] = true;
  } else {
    newMax.z() = float(newMin.z());
    newMin.z() = float(x2c_searchAabb.min.z());
    highFlags[2] = false;
  }

  u8 axisCounts[2] = {1, 1};
  if (nodeData & 0x1)
    axisCounts[0] = 2;
  if (nodeData & 0x2)
    axisCounts[1] = 2;

  zeus::CAABox& newSearch = const_cast<zeus::CAABox&>(x2c_searchAabb);
  if (nodeData & 0x1) {
    newSearch.min.x() = float(newMin.x());
    newSearch.max.x() = float(newMax.x());
  }
  if (nodeData & 0x2) {
    newSearch.min.y() = float(newMin.y());
    newSearch.max.y() = float(newMax.y());
  }
  if (nodeData & 0x4) {
    newSearch.min.z() = float(newMin.z());
    newSearch.max.z() = float(newMax.z());
  }

  // Branch node - calculate next relative pointer
  return highFlags[0] * bool(nodeData & 0x1) + highFlags[1] * axisCounts[0] * bool(nodeData & 0x2) +
         highFlags[2] * axisCounts[0] * axisCounts[1] * bool(nodeData & 0x4);
}

} // namespace urde
<commit_msg>CPVSVisOctree: Use static qualifying name for ReadBoundingBoxBig()<commit_after>#include "Runtime/Graphics/CPVSVisOctree.hpp"

namespace urde {

CPVSVisOctree CPVSVisOctree::MakePVSVisOctree(const u8* data) {
  CMemoryInStream r(data, 68);
  const zeus::CAABox aabb = zeus::CAABox::ReadBoundingBoxBig(r);
  const u32 numObjects = r.readUint32Big();
  const u32 numLights = r.readUint32Big();
  r.readUint32Big();
  return CPVSVisOctree(aabb, numObjects, numLights, data + r.position());
}

CPVSVisOctree::CPVSVisOctree(const zeus::CAABox& aabb, u32 numObjects, u32 numLights, const u8* c)
: x0_aabb(aabb), x18_numObjects(numObjects), x1c_numLights(numLights), x20_bufferFlag(c != nullptr), x24_octreeData(c) {
  x2c_searchAabb = x0_aabb;
  x20_bufferFlag = 0;
}

static const u32 NumChildTable[] = {0, 2, 2, 4, 2, 4, 4, 8};

u32 CPVSVisOctree::GetNumChildren(u8 byte) const { return NumChildTable[byte & 0x7]; }

u32 CPVSVisOctree::GetChildIndex(const u8*, const zeus::CVector3f&) const { return 0; }

s32 CPVSVisOctree::IterateSearch(u8 nodeData, const zeus::CVector3f& tp) const {
  if (!(nodeData & 0x7))
    return -1; // Leaf node

  zeus::CVector3f newMin = x2c_searchAabb.center();
  zeus::CVector3f newMax;
  bool highFlags[3];

  if (tp.x() > newMin.x()) {
    newMax.x() = x2c_searchAabb.max.x();
    highFlags[0] = true;
  } else {
    newMax.x() = float(newMin.x());
    newMin.x() = float(x2c_searchAabb.min.x());
    highFlags[0] = false;
  }

  if (tp.y() > newMin.y()) {
    newMax.y() = float(x2c_searchAabb.max.y());
    highFlags[1] = true;
  } else {
    newMax.y() = float(newMin.y());
    newMin.y() = float(x2c_searchAabb.min.y());
    highFlags[1] = false;
  }

  if (tp.z() > newMin.z()) {
    newMax.z() = float(x2c_searchAabb.max.z());
    highFlags[2] = true;
  } else {
    newMax.z() = float(newMin.z());
    newMin.z() = float(x2c_searchAabb.min.z());
    highFlags[2] = false;
  }

  u8 axisCounts[2] = {1, 1};
  if (nodeData & 0x1)
    axisCounts[0] = 2;
  if (nodeData & 0x2)
    axisCounts[1] = 2;

  zeus::CAABox& newSearch = const_cast<zeus::CAABox&>(x2c_searchAabb);
  if (nodeData & 0x1) {
    newSearch.min.x() = float(newMin.x());
    newSearch.max.x() = float(newMax.x());
  }
  if (nodeData & 0x2) {
    newSearch.min.y() = float(newMin.y());
    newSearch.max.y() = float(newMax.y());
  }
  if (nodeData & 0x4) {
    newSearch.min.z() = float(newMin.z());
    newSearch.max.z() = float(newMax.z());
  }

  // Branch node - calculate next relative pointer
  return highFlags[0] * bool(nodeData & 0x1) + highFlags[1] * axisCounts[0] * bool(nodeData & 0x2) +
         highFlags[2] * axisCounts[0] * axisCounts[1] * bool(nodeData & 0x4);
}

} // namespace urde
<|endoftext|>


<commit_before>#include "susi/LevelDBComponent.h"

Susi::LevelDBComponent::LevelDBComponent(Susi::SusiClient & susi, std::string dbPath) :
  susi_{susi},
  dbPath_{dbPath} {
	dbOptions_.create_if_missing = true;
	leveldb::DB *dbPtr;
	leveldb::DB::Open(dbOptions_, dbPath_, &dbPtr);
	db_.reset(dbPtr);
	susi_.registerProcessor("(leveldb|state)::put",[this](Susi::EventPtr event){
		handlePut(std::move(event));
	});
	susi_.registerProcessor("(leveldb|state)::get",[this](Susi::EventPtr event){
		handleGet(std::move(event));
	});
	susi_.registerProcessor("(leveldb|state)::delete",[this](Susi::EventPtr event){
		handleDelete(std::move(event));
	});
    susi_.registerProcessor("leveldb::getPrefix",[this](Susi::EventPtr event){
        handleGetPrefix(std::move(event));
    });
}

void Susi::LevelDBComponent::join(){
	susi_.join();
}

bool Susi::LevelDBComponent::validateFieldsForPut(const Susi::EventPtr & event){
	if(!(event->payload.isObject()) ||
	   !(event->payload["key"].isString()) ||
	   event->payload["value"].isUndefined()){
		return false;
	}
	return true;
}

bool Susi::LevelDBComponent::validateFieldsForGet(const Susi::EventPtr & event){
	if(!(event->payload.isObject()) ||
	   !(event->payload["key"].isString())){
		return false;
	}
	return true;
}

void Susi::LevelDBComponent::handlePut(Susi::EventPtr event){
	if(!validateFieldsForPut(event)){
		event->headers.push_back({"Error","leveldb put error"});
		return;
	}
	leveldb::Status s = db_.get()->Put(leveldb::WriteOptions(), event->payload["key"].getString(), event->payload["value"].toJSON());
	if(!s.ok()){
		event->headers.push_back({"Error","leveldb put error: "+s.ToString()});
		return;
	}
	event->payload["success"] = true;
}

void Susi::LevelDBComponent::handleGet(Susi::EventPtr event){
	if(!validateFieldsForGet(event)){
		event->headers.push_back({"Error","leveldb get error"});
		return;
	}
	std::string valueStr;
	leveldb::Status s = db_.get()->Get(leveldb::ReadOptions(), event->payload["key"].getString(), &valueStr);
	if(!s.ok()){
		event->headers.push_back({"Error","leveldb get error: "+s.ToString()});
		return;
	}
	event->payload["value"] = BSON::Value::fromJSON(valueStr);
}

void Susi::LevelDBComponent::handleDelete(Susi::EventPtr event){
	if(!validateFieldsForGet(event)){
		event->headers.push_back({"Error","leveldb delete error"});
		return;
	}
	leveldb::Status s = db_.get()->Delete(leveldb::WriteOptions(), event->payload["key"].getString());
	if(!s.ok()){
		event->headers.push_back({"Error","leveldb delete error: "+s.ToString()});
		return;
	}
	event->payload["success"] = true;
}

void Susi::LevelDBComponent::handleGetPrefix(Susi::EventPtr event){
	if(!validateFieldsForGet(event)){
		event->headers.push_back({"Error","leveldb get error"});
		return;
	}
    BSON::Value result;
    auto prefix = event->payload["key"].getString();
    std::shared_ptr<leveldb::Iterator> dbIter(db_->NewIterator(leveldb::ReadOptions()));
    for(dbIter->Seek(prefix); dbIter->Valid() && dbIter->key().starts_with(prefix) ; dbIter->Next()){
        if( !dbIter->value().empty() ) {
            auto key = dbIter->key();
            auto value = dbIter->value();
            std::string keyString{key.data(),key.size()};
            std::string valueString{value.data(),value.size()};
            result[keyString] = BSON::Value::fromJSON(valueString);
        }
    }
	event->payload["value"] = result;
}
<commit_msg>[susi-leveldb] added some debugging logs;<commit_after>#include "susi/LevelDBComponent.h"

Susi::LevelDBComponent::LevelDBComponent(Susi::SusiClient & susi, std::string dbPath) :
  susi_{susi},
  dbPath_{dbPath} {
	dbOptions_.create_if_missing = true;
	leveldb::DB *dbPtr;
	leveldb::DB::Open(dbOptions_, dbPath_, &dbPtr);
	db_.reset(dbPtr);
	susi_.registerProcessor("(leveldb|state)::put",[this](Susi::EventPtr event){
		handlePut(std::move(event));
	});
	susi_.registerProcessor("(leveldb|state)::get",[this](Susi::EventPtr event){
		handleGet(std::move(event));
	});
	susi_.registerProcessor("(leveldb|state)::delete",[this](Susi::EventPtr event){
		handleDelete(std::move(event));
	});
    susi_.registerProcessor("leveldb::getPrefix",[this](Susi::EventPtr event){
        handleGetPrefix(std::move(event));
    });
}

void Susi::LevelDBComponent::join(){
	susi_.join();
}

bool Susi::LevelDBComponent::validateFieldsForPut(const Susi::EventPtr & event){
	if(!(event->payload.isObject()) ||
	   !(event->payload["key"].isString()) ||
	   event->payload["value"].isUndefined()){
		return false;
	}
	return true;
}

bool Susi::LevelDBComponent::validateFieldsForGet(const Susi::EventPtr & event){
	if(!(event->payload.isObject()) ||
	   !(event->payload["key"].isString())){
		return false;
	}
	return true;
}

void Susi::LevelDBComponent::handlePut(Susi::EventPtr event){
	if(!validateFieldsForPut(event)){
		event->headers.push_back({"Error","leveldb put error"});
		return;
	}
	leveldb::Status s = db_.get()->Put(leveldb::WriteOptions(), event->payload["key"].getString(), event->payload["value"].toJSON());
	if(!s.ok()){
		event->headers.push_back({"Error","leveldb put error: "+s.ToString()});
		return;
	}
    std::cout << "wrote "<<event->payload["key"].getString()<<" to disk."<<std::endl;
	event->payload["success"] = true;
}

void Susi::LevelDBComponent::handleGet(Susi::EventPtr event){
	if(!validateFieldsForGet(event)){
		event->headers.push_back({"Error","leveldb get error"});
		return;
	}
	std::string valueStr;
	leveldb::Status s = db_.get()->Get(leveldb::ReadOptions(), event->payload["key"].getString(), &valueStr);
	if(!s.ok()){
		event->headers.push_back({"Error","leveldb get error: "+s.ToString()});
		return;
	}
    std::cout << "got "<<event->payload["key"].getString()<<" from disk."<<std::endl;
	event->payload["value"] = BSON::Value::fromJSON(valueStr);
}

void Susi::LevelDBComponent::handleDelete(Susi::EventPtr event){
	if(!validateFieldsForGet(event)){
		event->headers.push_back({"Error","leveldb delete error"});
		return;
	}
	leveldb::Status s = db_.get()->Delete(leveldb::WriteOptions(), event->payload["key"].getString());
	if(!s.ok()){
		event->headers.push_back({"Error","leveldb delete error: "+s.ToString()});
		return;
	}
    std::cout << "deleted "<<event->payload["key"].getString()<<" from disk."<<std::endl;
	event->payload["success"] = true;
}

void Susi::LevelDBComponent::handleGetPrefix(Susi::EventPtr event){
	if(!validateFieldsForGet(event)){
		event->headers.push_back({"Error","leveldb get error"});
		return;
	}
    BSON::Value result;
    auto prefix = event->payload["key"].getString();
    std::shared_ptr<leveldb::Iterator> dbIter(db_->NewIterator(leveldb::ReadOptions()));
    for(dbIter->Seek(prefix); dbIter->Valid() && dbIter->key().starts_with(prefix) ; dbIter->Next()){
        if( !dbIter->value().empty() ) {
            auto key = dbIter->key();
            auto value = dbIter->value();
            std::string keyString{key.data(),key.size()};
            std::string valueString{value.data(),value.size()};
            result[keyString] = BSON::Value::fromJSON(valueString);
        }
    }
    std::cout << "got all keys with prefix "<<prefix<<" from disk."<<std::endl;
	event->payload["value"] = result;
}
<|endoftext|>