<commit_before>//
// Copyright (c) 2013-2017 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_GLOBAL_COMMON_HPP
#define RJ_GLOBAL_COMMON_HPP

#include <rectojump/core/render.hpp>
#include <rectojump/shared/utils.hpp>

#include <mlk/types/types.h>

#include <SFML/Window.hpp>

namespace rj
{
	enum class state : std::size_t
	{
		main_menu,
		game_menu,
		game,
		editor,
		debug_info,
		error,
		num
	};

	static constexpr const char* state_as_string[std::size_t(state::num)]{
		"main_menu", "game_menu", "game", "editor", "debug_info", "error"};

	enum class game_state : std::size_t
	{
		none,
		pre_running,
		running,
		paused,
		ended,
		num
	};

	// forward
	class game_handler;
	using rndr = render<game_handler>;
	template <typename... T>
	class data_store;
	using data_store_type = data_store<sf::Texture, sf::Font, sf::Font>;

	// general
	using dur = float;

	// input
	using key = sf::Keyboard::Key;
	using btn = sf::Mouse::Button;
	enum class wheel : char
	{
		up,
		down
	};

	// vectors
	using vec2f = sf::Vector2f;
	using vec2i = sf::Vector2i;
	using vec2u = sf::Vector2u;

	// level
	using music_data = mlk::data_packet;
	using entity_prototype = std::vector<float>;
	using entity_proto_vec = std::vector<entity_prototype>;
	enum entity_prototype_value : std::size_t
	{
		figure,
		prop,
		x,
		y
	};

	// level data
	// |-> section headers
	static const mlk::data_packet header_rj_bg{'R', 'J', 'B', 'G'};
	static const mlk::data_packet header_rj_level{'R', 'J', 'L', 'E',
												  'V', 'E', 'L'};

	// |-> strings
	static constexpr const char* level_name_null{"(null)"};

	// ui
	template <typename Textbox_Type>
	void default_textbox(Textbox_Type& tb)
	{
		tb.setOutlineThickness(1.f);
		tb.setOutlineColor(to_rgb("#f15ede"));
		tb.setTextColor(to_rgb("#555555"));
		tb.setTextSize(13);
		tb.setCursorColor(to_rgb("#555555"));
	}

	template <typename Button_Type>
	void default_button(Button_Type& btn)
	{
		btn.setOutlineThickness(1.f);
		btn.setOutlineColor(to_rgb("#f15ede"));
		btn.setFontColor(to_rgb("#555555"));
		btn.setFontSize(13);
	}
}

#endif// RJ_GLOBAL_COMMON_HPP
<commit_msg>added header_music<commit_after>//
// Copyright (c) 2013-2017 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_GLOBAL_COMMON_HPP
#define RJ_GLOBAL_COMMON_HPP

#include <rectojump/core/render.hpp>
#include <rectojump/shared/utils.hpp>

#include <mlk/types/types.h>

#include <SFML/Window.hpp>

namespace rj
{
	enum class state : std::size_t
	{
		main_menu,
		game_menu,
		game,
		editor,
		debug_info,
		error,
		num
	};

	static constexpr const char* state_as_string[std::size_t(state::num)]{
		"main_menu", "game_menu", "game", "editor", "debug_info", "error"};

	enum class game_state : std::size_t
	{
		none,
		pre_running,
		running,
		paused,
		ended,
		num
	};

	// forward
	class game_handler;
	using rndr = render<game_handler>;
	template <typename... T>
	class data_store;
	using data_store_type = data_store<sf::Texture, sf::Font, sf::Font>;

	// general
	using dur = float;

	// input
	using key = sf::Keyboard::Key;
	using btn = sf::Mouse::Button;
	enum class wheel : char
	{
		up,
		down
	};

	// vectors
	using vec2f = sf::Vector2f;
	using vec2i = sf::Vector2i;
	using vec2u = sf::Vector2u;

	// level
	using music_data = mlk::data_packet;
	using entity_prototype = std::vector<float>;
	using entity_proto_vec = std::vector<entity_prototype>;
	enum entity_prototype_value : std::size_t
	{
		figure,
		prop,
		x,
		y
	};

	// level data
	// |-> section headers
	static const mlk::data_packet header_rj_bg{'R', 'J', 'B', 'G'};
	static const mlk::data_packet header_rj_level{'R', 'J', 'L', 'E',
												  'V', 'E', 'L'};
	static const mlk::data_packet header_music{'M', 'U', 'S', 'I', 'C'};

	// |-> strings
	static constexpr const char* level_name_null{"(null)"};

	// ui
	template <typename Textbox_Type>
	void default_textbox(Textbox_Type& tb)
	{
		tb.setOutlineThickness(1.f);
		tb.setOutlineColor(to_rgb("#f15ede"));
		tb.setTextColor(to_rgb("#555555"));
		tb.setTextSize(13);
		tb.setCursorColor(to_rgb("#555555"));
	}

	template <typename Button_Type>
	void default_button(Button_Type& btn)
	{
		btn.setOutlineThickness(1.f);
		btn.setOutlineColor(to_rgb("#f15ede"));
		btn.setFontColor(to_rgb("#555555"));
		btn.setFontSize(13);
	}
}

#endif// RJ_GLOBAL_COMMON_HPP
<|endoftext|>


<commit_before>/*!
    \file mpmc_ring_queue.inl
    \brief Multiple producers / multiple consumers wait-free ring queue inline implementation
    \author Ivan Shynkarenka
    \date 19.01.2016
    \copyright MIT License
*/

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4702) // C4702: unreachable code
#endif

namespace CppCommon {

template<typename T>
inline MPMCRingQueue<T>::MPMCRingQueue(size_t capacity) : _capacity(capacity), _mask(capacity - 1), _buffer(new Node[capacity]), _head(0), _tail(0)
{
    assert((capacity > 1) && "Ring queue capacity must be greater than one!");
    assert(((capacity & (capacity - 1)) == 0) && "Ring queue capacity must be a power of two!");

    memset(_pad0, 0, sizeof(cache_line_pad));
    memset(_pad1, 0, sizeof(cache_line_pad));
    memset(_pad2, 0, sizeof(cache_line_pad));
    memset(_pad3, 0, sizeof(cache_line_pad));

    // Populate the sequence initial values
    for (size_t i = 0; i < capacity; ++i)
        _buffer[i].sequence.store(i, std::memory_order_relaxed);
}

template<typename T>
inline size_t MPMCRingQueue<T>::size() const noexcept
{
    const size_t head = _head.load(std::memory_order_acquire);
    const size_t tail = _tail.load(std::memory_order_acquire);

    return head - tail;
}

template<typename T>
inline bool MPMCRingQueue<T>::Enqueue(const T& item)
{
    T temp = item;
    return Enqueue(std::forward<T>(temp));
}

template<typename T>
inline bool MPMCRingQueue<T>::Enqueue(T&& item)
{
    size_t head_sequence = _head.load(std::memory_order_relaxed);

    for (;;)
    {
        Node* node = &_buffer[head_sequence & _mask];
        size_t node_sequence = node->sequence.load(std::memory_order_acquire);

        // If node sequence and head sequence are the same then it means this slot is empty
        int64_t diff = (int64_t)node_sequence - (int64_t)head_sequence;
        if (diff == 0)
        {
            // Claim our spot by moving head. If head isn't the same
            // as we last checked then that means someone beat us to
            // the punch weak compare is faster, but can return spurious
            // results which in this instance is OK, because it's in the loop
            if (_head.compare_exchange_weak(head_sequence, head_sequence + 1, std::memory_order_relaxed))
            {
                // Store the item value
                node->value = std::move(item);

                // Increment the sequence so that the tail knows it's accessible
                node->sequence.store(head_sequence + 1, std::memory_order_release);
                return true;
            }
        }
        else if (diff < 0)
        {
            // If node sequence is less than head sequence then it means this slot is full
            // and therefore buffer is full
            return false;
        }
        else
        {
            // Under normal circumstances this branch should never be taken
            head_sequence = _head.load(std::memory_order_relaxed);
        }
    }

    // Never happens...
    return false;
}

template<typename T>
inline bool MPMCRingQueue<T>::Dequeue(T& item)
{
    size_t tail_sequence = _tail.load(std::memory_order_relaxed);

    for (;;)
    {
        Node* node = &_buffer[tail_sequence & _mask];
        size_t node_sequence = node->sequence.load(std::memory_order_acquire);

        // If node sequence and head sequence are the same then it means this slot is empty
        int64_t diff = (int64_t)node_sequence - (int64_t)(tail_sequence + 1);
        if (diff == 0)
        {
            // Claim our spot by moving head. If head isn't the same
            // as we last checked then that means someone beat us to
            // the punch weak compare is faster, but can return spurious
            // results which in this instance is OK, because it's in the loop
            if (_tail.compare_exchange_weak(tail_sequence, tail_sequence + 1, std::memory_order_relaxed))
            {
                // Get the item value
                item = std::move(node->value);

                // Set the sequence to what the head sequence should be next time around
                node->sequence.store(tail_sequence + _mask + 1, std::memory_order_release);
                return true;
            }
        }
        else if (diff < 0)
        {
            // if seq is less than head seq then it means this slot is full and therefore the buffer is full
            return false;
        }
        else
        {
            // Under normal circumstances this branch should never be taken
            tail_sequence = _tail.load(std::memory_order_relaxed);
        }
    }

    // Never happens...
    return false;
}

} // namespace CppCommon

#if defined(_MSC_VER)
#pragma warning(pop)
#endif
<commit_msg>update<commit_after>/*!
    \file mpmc_ring_queue.inl
    \brief Multiple producers / multiple consumers wait-free ring queue inline implementation
    \author Ivan Shynkarenka
    \date 19.01.2016
    \copyright MIT License
*/

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4702) // C4702: unreachable code
#endif

namespace CppCommon {

template<typename T>
inline MPMCRingQueue<T>::MPMCRingQueue(size_t capacity) : _capacity(capacity), _mask(capacity - 1), _buffer(new Node[capacity]), _head(0), _tail(0)
{
    assert((capacity > 1) && "Ring queue capacity must be greater than one!");
    assert(((capacity & (capacity - 1)) == 0) && "Ring queue capacity must be a power of two!");

    memset(_pad0, 0, sizeof(cache_line_pad));
    memset(_pad1, 0, sizeof(cache_line_pad));
    memset(_pad2, 0, sizeof(cache_line_pad));
    memset(_pad3, 0, sizeof(cache_line_pad));

    // Populate the sequence initial values
    for (size_t i = 0; i < capacity; ++i)
        _buffer[i].sequence.store(i, std::memory_order_relaxed);
}

template<typename T>
inline size_t MPMCRingQueue<T>::size() const noexcept
{
    const size_t head = _head.load(std::memory_order_acquire);
    const size_t tail = _tail.load(std::memory_order_acquire);

    return head - tail;
}

template<typename T>
inline bool MPMCRingQueue<T>::Enqueue(const T& item)
{
    T temp = item;
    return Enqueue(std::forward<T>(temp));
}

template<typename T>
inline bool MPMCRingQueue<T>::Enqueue(T&& item)
{
    size_t head_sequence = _head.load(std::memory_order_relaxed);

    for (;;)
    {
        Node* node = &_buffer[head_sequence & _mask];
        size_t node_sequence = node->sequence.load(std::memory_order_acquire);

        // If node sequence and head sequence are the same then it means this slot is empty
        int64_t diff = (int64_t)node_sequence - (int64_t)head_sequence;
        if (diff == 0)
        {
            // Claim our spot by moving head. If head isn't the same
            // as we last checked then that means someone beat us to
            // the punch weak compare is faster, but can return spurious
            // results which in this instance is OK, because it's in the loop
            if (_head.compare_exchange_weak(head_sequence, head_sequence + 1, std::memory_order_relaxed))
            {
                // Store the item value
                node->value = std::move(item);

                // Increment the sequence so that the tail knows it's accessible
                node->sequence.store(head_sequence + 1, std::memory_order_release);
                return true;
            }
        }
        else if (diff < 0)
        {
            // If node sequence is less than head sequence then it means this slot is full
            // and therefore buffer is full
            return false;
        }
        else
        {
            // Under normal circumstances this branch should never be taken
            head_sequence = _head.load(std::memory_order_relaxed);
        }
    }

    // Never happens...
    return false;
}

template<typename T>
inline bool MPMCRingQueue<T>::Dequeue(T& item)
{
    size_t tail_sequence = _tail.load(std::memory_order_relaxed);

    for (;;)
    {
        Node* node = &_buffer[tail_sequence & _mask];
        size_t node_sequence = node->sequence.load(std::memory_order_acquire);

        // If node sequence and head sequence are the same then it means this slot is empty
        int64_t diff = (int64_t)node_sequence - (int64_t)(tail_sequence + 1);
        if (diff == 0)
        {
            // Claim our spot by moving head. If head isn't the same
            // as we last checked then that means someone beat us to
            // the punch weak compare is faster, but can return spurious
            // results which in this instance is OK, because it's in the loop
            if (_tail.compare_exchange_weak(tail_sequence, tail_sequence + 1, std::memory_order_relaxed))
            {
                // Get the item value
                item = std::move(node->value);

                // Set the sequence to what the head sequence should be next time around
                node->sequence.store(tail_sequence + _mask + 1, std::memory_order_release);
                return true;
            }
        }
        else if (diff < 0)
        {
            // If seq is less than head seq then it means this slot is full and therefore the buffer is full
            return false;
        }
        else
        {
            // Under normal circumstances this branch should never be taken
            tail_sequence = _tail.load(std::memory_order_relaxed);
        }
    }

    // Never happens...
    return false;
}

} // namespace CppCommon

#if defined(_MSC_VER)
#pragma warning(pop)
#endif
<|endoftext|>


<commit_before>/*
    Title:  memmgr.cpp   Memory segment manager

    Copyright (c) 2006-7 David C. J. Matthews

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/
#ifdef WIN32
#include "winconfig.h"
#else
#include "config.h"
#endif

#ifdef HAVE_ASSERT_H
#include <assert.h>
#define ASSERT(x)   assert(x)
#else
#define ASSERT(x)
#endif

#include "globals.h"
#include "memmgr.h"
#include "osmem.h"
#include "scanaddrs.h"
#include "bitmap.h"

MemSpace::MemSpace()
{
    spaceType = ST_PERMANENT;
    isMutable = false;
    bottom = 0;
    top = 0;
    isOwnSpace = false;
}

MemSpace::~MemSpace()
{
    if (isOwnSpace && bottom != 0)
        osMemoryManager->Free(bottom, (char*)top - (char*)bottom);
}

LocalMemSpace::LocalMemSpace()
{
    spaceType = ST_LOCAL;
    gen_top = 0;
    gen_bottom = 0;
    highest = 0;
    pointer = 0;
    for (unsigned i = 0; i < NSTARTS; i++)
        start[i] = 0;
    start_index = 0;
    i_marked = m_marked = copied = updated = 0;
}

bool LocalMemSpace::InitSpace(POLYUNSIGNED size, bool mut)
{
    isMutable = mut;
    // Allocate the heap itself.
    size_t iSpace = size*sizeof(PolyWord);
    bottom  =
        (PolyWord*)osMemoryManager->Allocate(iSpace, PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC);

    if (bottom == 0)
        return false;
    isOwnSpace = true; // Deallocate when we're finished.

    // The size may have been rounded up to a block boundary.
    size = iSpace/sizeof(PolyWord);

    top = bottom + size;
    gen_top = top;
    pointer = top;
    gen_bottom = top;

    // Bitmap for the space.
    return bitmap.Create(size);
}

MemMgr::MemMgr()
{
    npSpaces = nlSpaces = 0;
    minLocal = maxLocal = 0;
    pSpaces = 0;
    lSpaces = 0;
    eSpaces = 0;
    nextIndex = 0;
}

MemMgr::~MemMgr()
{
    unsigned i;
    for (i = 0; i < npSpaces; i++)
        delete(pSpaces[i]);
    for (i = 0; i < nlSpaces; i++)
        delete(lSpaces[i]);
    for (i = 0; i < neSpaces; i++)
        delete(eSpaces[i]);
}

// Create and initialise a new local space and add it to the table.
LocalMemSpace* MemMgr::NewLocalSpace(POLYUNSIGNED size, bool mut)
{
    LocalMemSpace *space = new LocalMemSpace;
    if (space->InitSpace(size, mut) && AddLocalSpace(space))
        return space;
    // If something went wrong.
    delete space;
    return 0;
}

// Add a local memory space to the table.
bool MemMgr::AddLocalSpace(LocalMemSpace *space)
{
    // Compute the maximum and minimum local addresses.  The idea
    // is to speed up LocalSpaceForAddress which is likely to be a hot-spot
    // in the GC.
    if (nlSpaces == 0)
    {
        // First space
        minLocal = space->bottom;
        maxLocal = space->top;
    }
    else
    {
        if (space->bottom < minLocal)
            minLocal = space->bottom;
        if (space->top > maxLocal)
            maxLocal = space->top;
    }

    // Add to the table.
    LocalMemSpace **table = (LocalMemSpace **)realloc(lSpaces, (nlSpaces+1) * sizeof(LocalMemSpace *));
    if (table == 0) return false;
    lSpaces = table;
    lSpaces[nlSpaces++] = space;
    return true;
}

// Create an entry for a permanent space.
PermanentMemSpace* MemMgr::NewPermanentSpace(PolyWord *base, POLYUNSIGNED words,
                                             bool mut, bool noOv, unsigned index, unsigned hierarchy /*= 0*/)
{
    PermanentMemSpace *space = new PermanentMemSpace;
    space->bottom = base;
    space->topPointer = space->top = space->bottom + words;
    space->spaceType = ST_PERMANENT;
    space->isMutable = mut;
    space->noOverwrite = noOv;
    space->index = index;
    space->hierarchy = hierarchy;
    if (index >= nextIndex) nextIndex = index+1;

    // Extend the permanent memory table and add this space to it.
    PermanentMemSpace **table =
        (PermanentMemSpace **)realloc(pSpaces, (npSpaces+1) * sizeof(PermanentMemSpace *));
    if (table == 0)
    {
        delete space;
        return 0;
    }
    pSpaces = table;
    pSpaces[npSpaces++] = space;
    return space;
}

// Delete a local space and remove it from the table.
bool MemMgr::DeleteLocalSpace(LocalMemSpace *sp)
{
    for (unsigned i = 0; i < nlSpaces; i++)
    {
        if (lSpaces[i] == sp)
        {
            delete sp;
            nlSpaces--;
            while (i < nlSpaces)
            {
                lSpaces[i] = lSpaces[i+1];
                i++;
            }
            return true;
        }
    }
    return false;
}

// Create an entry for the IO space.
MemSpace* MemMgr::InitIOSpace(PolyWord *base, POLYUNSIGNED words)
{
    ioSpace.bottom = base;
    ioSpace.top = ioSpace.bottom + words;
    ioSpace.spaceType = ST_IO;
    ioSpace.isMutable = false;
    return &ioSpace;
}

// Create and initialise a new export space and add it to the table.
PermanentMemSpace* MemMgr::NewExportSpace(POLYUNSIGNED size, bool mut, bool noOv)
{
    PermanentMemSpace *space = new PermanentMemSpace;
    space->spaceType = ST_EXPORT;
    space->isMutable = mut;
    space->noOverwrite = noOv;
    space->index = nextIndex++;
    // Allocate the memory itself.
    size_t iSpace = size*sizeof(PolyWord);
    space->bottom  =
        (PolyWord*)osMemoryManager->Allocate(iSpace, PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC);

    if (space->bottom == 0)
    {
        delete space;
        return 0;
    }
    space->isOwnSpace = true;

    // The size may have been rounded up to a block boundary.
    size = iSpace/sizeof(PolyWord);
    space->top = space->bottom + size;
    space->topPointer = space->bottom;

    // Add to the table.
    PermanentMemSpace **table = (PermanentMemSpace **)realloc(eSpaces, (neSpaces+1) * sizeof(PermanentMemSpace *));
    if (table == 0)
    {
        delete space;
        return 0;
    }
    eSpaces = table;
    eSpaces[neSpaces++] = space;
    return space;
}

void MemMgr::DeleteExportSpaces(void)
{
    while (neSpaces > 0)
        delete(eSpaces[--neSpaces]);
}

// If we have saved the state rather than exported a function we turn the exported
// spaces into permanent ones, removing existing permanent spaces at the same or
// lower level.
bool MemMgr::PromoteExportSpaces(unsigned hierarchy)
{
    // Create a new table big enough to hold all the permanent and export spaces
    PermanentMemSpace **pTable =
        (PermanentMemSpace **)calloc(npSpaces+neSpaces, sizeof(PermanentMemSpace *));
    if (pTable == 0) return false;
    unsigned newSpaces = 0;
    // Save permanent spaces at a lower hierarchy.  Others are converted into
    // local spaces.  Most or all items will have been copied from these spaces
    // into an export space but there could be items reachable only from the stack.
    for (unsigned i = 0; i < npSpaces; i++)
    {
        PermanentMemSpace *pSpace = pSpaces[i];
        if (pSpace->hierarchy < hierarchy)
            pTable[newSpaces++] = pSpace;
        else
        {
            // Turn this into a local space.
            LocalMemSpace *space = new LocalMemSpace;
            space->top = space->gen_top = space->gen_bottom = pSpace->top;
            space->bottom = space->pointer = pSpace->bottom;
            space->isMutable = pSpace->isMutable;
            space->isOwnSpace = true;
            if (! space->bitmap.Create(space->top-space->bottom) || ! AddLocalSpace(space))
                return false;
        }
    }
    // Save newly exported spaces.
    for (unsigned j = 0; j < neSpaces; j++)
    {
        PermanentMemSpace *space = eSpaces[j];
        space->hierarchy = hierarchy; // Set the hierarchy of the new spaces.
        space->spaceType = ST_PERMANENT;
        // Put a dummy object to fill up the unused space.
        if (space->topPointer != space->top)
            FillUnusedSpace(space->topPointer, space->top - space->topPointer);
        // Put in a dummy object to fill the rest of the space.
        pTable[newSpaces++] = space;
    }
    neSpaces = 0;
    npSpaces = newSpaces;
    free(pSpaces);
    pSpaces = pTable;

    return true;
}

// Before we import a hierarchical saved state we need to turn any previously imported
// spaces into local spaces.
bool MemMgr::DemoteImportSpaces()
{
    // Create a new permanent space table.
    PermanentMemSpace **table =
        (PermanentMemSpace **)calloc(npSpaces, sizeof(PermanentMemSpace *));
    if (table == NULL) return false;
    unsigned newSpaces = 0;
    for (unsigned i = 0; i < npSpaces; i++)
    {
        PermanentMemSpace *pSpace = pSpaces[i];
        if (pSpace->hierarchy == 0) // Leave truly permanent spaces
            table[newSpaces++] = pSpace;
        else
        {
            // Turn this into a local space.
            LocalMemSpace *space = new LocalMemSpace;
            space->top = space->gen_top = space->gen_bottom = pSpace->top;
            space->bottom = space->pointer = pSpace->bottom;
            space->isMutable = pSpace->isMutable;
            space->isOwnSpace = true;
            if (! space->bitmap.Create(space->top-space->bottom) || ! AddLocalSpace(space))
                return false;
        }
    }
    npSpaces = newSpaces;
    free(pSpaces);
    pSpaces = table;

    return true;
}

// Return the space the address is in or NULL if none.
// We have to check here against the bottom of the area rather
// than the allocation because, when called from CopyObject,
// the "pointer" field points to the top of the area.
// N.B.  By checking for pt < space->top we are assuming that we don't have
// zero length objects.  A zero length object at the top of the space would
// have its length word as the last word in the space and the address of the
// object would be == space->top.
MemSpace *MemMgr::SpaceForAddress(const void *pt)
{
    unsigned i;
    for (i = 0; i < nlSpaces; i++)
    {
        MemSpace *space = lSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return space;
    }
    for (i = 0; i < npSpaces; i++)
    {
        MemSpace *space = pSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return space;
    }
    for (i = 0; i < neSpaces; i++)
    {
        MemSpace *space = eSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return space;
    }
    if (pt >= ioSpace.bottom && pt < ioSpace.top)
        return &ioSpace;
    return 0; // Not in any space
}

bool MemMgr::IsPermanentMemoryPointer(const void *pt)
{
    for (unsigned i = 0; i < npSpaces; i++)
    {
        MemSpace *space = pSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return true;
    }
    return false;
}

// Return the space for a given index
PermanentMemSpace *MemMgr::SpaceForIndex(unsigned index)
{
    for (unsigned i = 0; i < npSpaces; i++)
    {
        PermanentMemSpace *space = pSpaces[i];
        if (space->index == index)
            return space;
    }
    return NULL;
}

// In several places we assume that segments are filled with valid
// objects.  This fills unused memory with one or more "byte" objects.
void MemMgr::FillUnusedSpace(PolyWord *base, POLYUNSIGNED words)
{
    PolyWord *pDummy = base+1;
    while (words > 0)
    {
        POLYUNSIGNED oSize = words;
        // If the space is larger than the maximum object size
        // we will need several objects.
        if (words > MAX_OBJECT_SIZE) oSize = MAX_OBJECT_SIZE;
        else oSize = words-1;
        // Make this a byte object so it's always skipped.
        ((PolyObject*)pDummy)->SetLengthWord(oSize, F_BYTE_OBJ);
        words -= oSize+1;
        pDummy += oSize+1;
    }
}

// Allocate an area of the heap of at least minWords and at most maxWords.
// This is used both when allocating single objects (when minWords and maxWords
// are the same) and when allocating heap segments.  If there is insufficient
// space to satisfy the minimum it will return 0.
PolyWord *MemMgr::AllocHeapSpace(POLYUNSIGNED minWords, POLYUNSIGNED &maxWords)
{
    allocLock.Lock();
    for (unsigned j = 0; j < gMem.nlSpaces; j++)
    {
        LocalMemSpace *space = gMem.lSpaces[j];
        if (space->isMutable)
        {
            POLYUNSIGNED available = space->pointer - space->bottom;
            if (available > 0 && available >= minWords)
            {
                // Reduce the maximum value if we had less than that.
                if (available < maxWords)
                    maxWords = available;
                space->pointer -= maxWords; // Allocate it.
                PolyWord *result = space->pointer; // Return the address.
                allocLock.Unlock();
                return result;
            }
        }
    }
    allocLock.Unlock();
    return 0; // There isn't space even for the minimum.
}

MemMgr gMem; // The one and only memory manager object

<commit_msg>Fix to DemoteImportSpaces.  The local memory space to hold an old saved state was not being set up correctly and the GC was overwriting it. <commit_after>/*
    Title:  memmgr.cpp   Memory segment manager

    Copyright (c) 2006-7 David C. J. Matthews

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/
#ifdef WIN32
#include "winconfig.h"
#else
#include "config.h"
#endif

#ifdef HAVE_ASSERT_H
#include <assert.h>
#define ASSERT(x)   assert(x)
#else
#define ASSERT(x)
#endif

#include "globals.h"
#include "memmgr.h"
#include "osmem.h"
#include "scanaddrs.h"
#include "bitmap.h"

MemSpace::MemSpace()
{
    spaceType = ST_PERMANENT;
    isMutable = false;
    bottom = 0;
    top = 0;
    isOwnSpace = false;
}

MemSpace::~MemSpace()
{
    if (isOwnSpace && bottom != 0)
        osMemoryManager->Free(bottom, (char*)top - (char*)bottom);
}

LocalMemSpace::LocalMemSpace()
{
    spaceType = ST_LOCAL;
    gen_top = 0;
    gen_bottom = 0;
    highest = 0;
    pointer = 0;
    for (unsigned i = 0; i < NSTARTS; i++)
        start[i] = 0;
    start_index = 0;
    i_marked = m_marked = copied = updated = 0;
}

bool LocalMemSpace::InitSpace(POLYUNSIGNED size, bool mut)
{
    isMutable = mut;
    // Allocate the heap itself.
    size_t iSpace = size*sizeof(PolyWord);
    bottom  =
        (PolyWord*)osMemoryManager->Allocate(iSpace, PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC);

    if (bottom == 0)
        return false;
    isOwnSpace = true; // Deallocate when we're finished.

    // The size may have been rounded up to a block boundary.
    size = iSpace/sizeof(PolyWord);

    top = bottom + size;
    gen_top = top;
    pointer = top;
    gen_bottom = top;

    // Bitmap for the space.
    return bitmap.Create(size);
}

MemMgr::MemMgr()
{
    npSpaces = nlSpaces = 0;
    minLocal = maxLocal = 0;
    pSpaces = 0;
    lSpaces = 0;
    eSpaces = 0;
    nextIndex = 0;
}

MemMgr::~MemMgr()
{
    unsigned i;
    for (i = 0; i < npSpaces; i++)
        delete(pSpaces[i]);
    for (i = 0; i < nlSpaces; i++)
        delete(lSpaces[i]);
    for (i = 0; i < neSpaces; i++)
        delete(eSpaces[i]);
}

// Create and initialise a new local space and add it to the table.
LocalMemSpace* MemMgr::NewLocalSpace(POLYUNSIGNED size, bool mut)
{
    LocalMemSpace *space = new LocalMemSpace;
    if (space->InitSpace(size, mut) && AddLocalSpace(space))
        return space;
    // If something went wrong.
    delete space;
    return 0;
}

// Add a local memory space to the table.
bool MemMgr::AddLocalSpace(LocalMemSpace *space)
{
    // Compute the maximum and minimum local addresses.  The idea
    // is to speed up LocalSpaceForAddress which is likely to be a hot-spot
    // in the GC.
    if (nlSpaces == 0)
    {
        // First space
        minLocal = space->bottom;
        maxLocal = space->top;
    }
    else
    {
        if (space->bottom < minLocal)
            minLocal = space->bottom;
        if (space->top > maxLocal)
            maxLocal = space->top;
    }

    // Add to the table.
    LocalMemSpace **table = (LocalMemSpace **)realloc(lSpaces, (nlSpaces+1) * sizeof(LocalMemSpace *));
    if (table == 0) return false;
    lSpaces = table;
    lSpaces[nlSpaces++] = space;
    return true;
}

// Create an entry for a permanent space.
PermanentMemSpace* MemMgr::NewPermanentSpace(PolyWord *base, POLYUNSIGNED words,
                                             bool mut, bool noOv, unsigned index, unsigned hierarchy /*= 0*/)
{
    PermanentMemSpace *space = new PermanentMemSpace;
    space->bottom = base;
    space->topPointer = space->top = space->bottom + words;
    space->spaceType = ST_PERMANENT;
    space->isMutable = mut;
    space->noOverwrite = noOv;
    space->index = index;
    space->hierarchy = hierarchy;
    if (index >= nextIndex) nextIndex = index+1;

    // Extend the permanent memory table and add this space to it.
    PermanentMemSpace **table =
        (PermanentMemSpace **)realloc(pSpaces, (npSpaces+1) * sizeof(PermanentMemSpace *));
    if (table == 0)
    {
        delete space;
        return 0;
    }
    pSpaces = table;
    pSpaces[npSpaces++] = space;
    return space;
}

// Delete a local space and remove it from the table.
bool MemMgr::DeleteLocalSpace(LocalMemSpace *sp)
{
    for (unsigned i = 0; i < nlSpaces; i++)
    {
        if (lSpaces[i] == sp)
        {
            delete sp;
            nlSpaces--;
            while (i < nlSpaces)
            {
                lSpaces[i] = lSpaces[i+1];
                i++;
            }
            return true;
        }
    }
    return false;
}

// Create an entry for the IO space.
MemSpace* MemMgr::InitIOSpace(PolyWord *base, POLYUNSIGNED words)
{
    ioSpace.bottom = base;
    ioSpace.top = ioSpace.bottom + words;
    ioSpace.spaceType = ST_IO;
    ioSpace.isMutable = false;
    return &ioSpace;
}

// Create and initialise a new export space and add it to the table.
PermanentMemSpace* MemMgr::NewExportSpace(POLYUNSIGNED size, bool mut, bool noOv)
{
    PermanentMemSpace *space = new PermanentMemSpace;
    space->spaceType = ST_EXPORT;
    space->isMutable = mut;
    space->noOverwrite = noOv;
    space->index = nextIndex++;
    // Allocate the memory itself.
    size_t iSpace = size*sizeof(PolyWord);
    space->bottom  =
        (PolyWord*)osMemoryManager->Allocate(iSpace, PERMISSION_READ|PERMISSION_WRITE|PERMISSION_EXEC);

    if (space->bottom == 0)
    {
        delete space;
        return 0;
    }
    space->isOwnSpace = true;

    // The size may have been rounded up to a block boundary.
    size = iSpace/sizeof(PolyWord);
    space->top = space->bottom + size;
    space->topPointer = space->bottom;

    // Add to the table.
    PermanentMemSpace **table = (PermanentMemSpace **)realloc(eSpaces, (neSpaces+1) * sizeof(PermanentMemSpace *));
    if (table == 0)
    {
        delete space;
        return 0;
    }
    eSpaces = table;
    eSpaces[neSpaces++] = space;
    return space;
}

void MemMgr::DeleteExportSpaces(void)
{
    while (neSpaces > 0)
        delete(eSpaces[--neSpaces]);
}

// If we have saved the state rather than exported a function we turn the exported
// spaces into permanent ones, removing existing permanent spaces at the same or
// lower level.
bool MemMgr::PromoteExportSpaces(unsigned hierarchy)
{
    // Create a new table big enough to hold all the permanent and export spaces
    PermanentMemSpace **pTable =
        (PermanentMemSpace **)calloc(npSpaces+neSpaces, sizeof(PermanentMemSpace *));
    if (pTable == 0) return false;
    unsigned newSpaces = 0;
    // Save permanent spaces at a lower hierarchy.  Others are converted into
    // local spaces.  Most or all items will have been copied from these spaces
    // into an export space but there could be items reachable only from the stack.
    for (unsigned i = 0; i < npSpaces; i++)
    {
        PermanentMemSpace *pSpace = pSpaces[i];
        if (pSpace->hierarchy < hierarchy)
            pTable[newSpaces++] = pSpace;
        else
        {
            // Turn this into a local space.
            LocalMemSpace *space = new LocalMemSpace;
            space->top = space->gen_top = space->gen_bottom = pSpace->top;
            space->bottom = space->pointer = pSpace->bottom;
            space->isMutable = pSpace->isMutable;
            space->isOwnSpace = true;
            if (! space->bitmap.Create(space->top-space->bottom) || ! AddLocalSpace(space))
                return false;
        }
    }
    // Save newly exported spaces.
    for (unsigned j = 0; j < neSpaces; j++)
    {
        PermanentMemSpace *space = eSpaces[j];
        space->hierarchy = hierarchy; // Set the hierarchy of the new spaces.
        space->spaceType = ST_PERMANENT;
        // Put a dummy object to fill up the unused space.
        if (space->topPointer != space->top)
            FillUnusedSpace(space->topPointer, space->top - space->topPointer);
        // Put in a dummy object to fill the rest of the space.
        pTable[newSpaces++] = space;
    }
    neSpaces = 0;
    npSpaces = newSpaces;
    free(pSpaces);
    pSpaces = pTable;

    return true;
}

// Before we import a hierarchical saved state we need to turn any previously imported
// spaces into local spaces.
bool MemMgr::DemoteImportSpaces()
{
    // Create a new permanent space table.
    PermanentMemSpace **table =
        (PermanentMemSpace **)calloc(npSpaces, sizeof(PermanentMemSpace *));
    if (table == NULL) return false;
    unsigned newSpaces = 0;
    for (unsigned i = 0; i < npSpaces; i++)
    {
        PermanentMemSpace *pSpace = pSpaces[i];
        if (pSpace->hierarchy == 0) // Leave truly permanent spaces
            table[newSpaces++] = pSpace;
        else
        {
            // Turn this into a local space.
            LocalMemSpace *space = new LocalMemSpace;
            space->top = pSpace->top;
            // Space is allocated in local areas from the top down.  This area is full and
            // all data is in the old generation.  The area can be recovered by a full GC.
            space->bottom = space->pointer = space->gen_top = space->gen_bottom = pSpace->bottom;
            space->isMutable = pSpace->isMutable;
            space->isOwnSpace = true;
            if (! space->bitmap.Create(space->top-space->bottom) || ! AddLocalSpace(space))
                return false;
        }
    }
    npSpaces = newSpaces;
    free(pSpaces);
    pSpaces = table;

    return true;
}

// Return the space the address is in or NULL if none.
// We have to check here against the bottom of the area rather
// than the allocation because, when called from CopyObject,
// the "pointer" field points to the top of the area.
// N.B.  By checking for pt < space->top we are assuming that we don't have
// zero length objects.  A zero length object at the top of the space would
// have its length word as the last word in the space and the address of the
// object would be == space->top.
MemSpace *MemMgr::SpaceForAddress(const void *pt)
{
    unsigned i;
    for (i = 0; i < nlSpaces; i++)
    {
        MemSpace *space = lSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return space;
    }
    for (i = 0; i < npSpaces; i++)
    {
        MemSpace *space = pSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return space;
    }
    for (i = 0; i < neSpaces; i++)
    {
        MemSpace *space = eSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return space;
    }
    if (pt >= ioSpace.bottom && pt < ioSpace.top)
        return &ioSpace;
    return 0; // Not in any space
}

bool MemMgr::IsPermanentMemoryPointer(const void *pt)
{
    for (unsigned i = 0; i < npSpaces; i++)
    {
        MemSpace *space = pSpaces[i];
        if (pt >= space->bottom && pt < space->top)
            return true;
    }
    return false;
}

// Return the space for a given index
PermanentMemSpace *MemMgr::SpaceForIndex(unsigned index)
{
    for (unsigned i = 0; i < npSpaces; i++)
    {
        PermanentMemSpace *space = pSpaces[i];
        if (space->index == index)
            return space;
    }
    return NULL;
}

// In several places we assume that segments are filled with valid
// objects.  This fills unused memory with one or more "byte" objects.
void MemMgr::FillUnusedSpace(PolyWord *base, POLYUNSIGNED words)
{
    PolyWord *pDummy = base+1;
    while (words > 0)
    {
        POLYUNSIGNED oSize = words;
        // If the space is larger than the maximum object size
        // we will need several objects.
        if (words > MAX_OBJECT_SIZE) oSize = MAX_OBJECT_SIZE;
        else oSize = words-1;
        // Make this a byte object so it's always skipped.
        ((PolyObject*)pDummy)->SetLengthWord(oSize, F_BYTE_OBJ);
        words -= oSize+1;
        pDummy += oSize+1;
    }
}

// Allocate an area of the heap of at least minWords and at most maxWords.
// This is used both when allocating single objects (when minWords and maxWords
// are the same) and when allocating heap segments.  If there is insufficient
// space to satisfy the minimum it will return 0.
PolyWord *MemMgr::AllocHeapSpace(POLYUNSIGNED minWords, POLYUNSIGNED &maxWords)
{
    allocLock.Lock();
    for (unsigned j = 0; j < gMem.nlSpaces; j++)
    {
        LocalMemSpace *space = gMem.lSpaces[j];
        if (space->isMutable)
        {
            POLYUNSIGNED available = space->pointer - space->bottom;
            if (available > 0 && available >= minWords)
            {
                // Reduce the maximum value if we had less than that.
                if (available < maxWords)
                    maxWords = available;
                space->pointer -= maxWords; // Allocate it.
                PolyWord *result = space->pointer; // Return the address.
                allocLock.Unlock();
                return result;
            }
        }
    }
    allocLock.Unlock();
    return 0; // There isn't space even for the minimum.
}

MemMgr gMem; // The one and only memory manager object

<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

#include "objectives.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "fortune.hpp"
#include "accounts.hpp"
#include "args.hpp"
#include "data.hpp"
#include "guid.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "console.hpp"
#include "budget_exception.hpp"

using namespace budget;

namespace {

static data_handler<objective> objectives;

void list_objectives(){
    if(objectives.data.size() == 0){
        std::cout << "No objectives" << std::endl;
    } else {
        std::vector<std::string> columns = {"ID", "Name", "Type", "Source", "Operator", "Amount"};
        std::vector<std::vector<std::string>> contents;

        for(auto& objective : objectives.data){
            contents.push_back({to_string(objective.id), objective.name, objective.type, objective.source, objective.op, to_string(objective.amount)});
        }

        display_table(columns, contents);
    }
}

template<typename T>
void print_minimum(const T& str, std::size_t min_width){
    auto old_width = std::cout.width();
    std::cout.width(min_width);
    std::cout << str;
    std::cout.width(old_width);
}

void print_success(budget::money balance, budget::money earnings, budget::money expenses, const budget::objective& objective){
    auto amount = objective.amount;

    budget::money basis;
    if(objective.source == "expenses"){
        basis = expenses;
    } else if (objective.source == "earnings") {
        basis = earnings;
    } else {
        basis = balance;
    }

    int success = 0;
    if(objective.op == "min"){
        auto percent = basis.dollars() / static_cast<double>(amount.dollars());
        success = percent * 100;
    } else if(objective.op == "max"){
        auto percent = amount.dollars() / static_cast<double>(basis.dollars());
        success = percent * 100;
    }

    success = std::max(0, success);
    print_minimum(success, 5);
    std::cout << "%  ";

    success = std::min(success, 109);
    auto good = success == 0 ? 0 : (success / 10) + 1;

    for(std::size_t i = 0; i < good; ++i){
        std::cout << "\033[1;42m   \033[0m";
    }

    for(std::size_t i = good; i < 11; ++i){
        std::cout << "\033[1;41m   \033[0m";
    }
}

void status_objectives(){
    if(objectives.data.size() == 0){
        std::cout << "No objectives" << std::endl;
    } else {
        auto today = boost::gregorian::day_clock::local_day();
        auto current_month = today.month();
        auto current_year = today.year();
        auto sm = start_month(current_year);

        size_t monthly = 0;
        size_t yearly = 0;

        for(auto& objective : objectives.data){
            if(objective.type == "yearly"){
                ++yearly;
            } else if(objective.type == "monthly"){
                ++monthly;
            }
        }

        if(yearly){
            std::cout << "Year objectives" << std::endl << std::endl;

            size_t width = 0;
            for(auto& objective : objectives.data){
                if(objective.type == "yearly"){
                    width = std::max(rsize(objective.name), width);
                }
            }

            budget::money expenses;
            for(auto& expense : all_expenses()){
                if(expense.date.year() == current_year && expense.date.month() >= sm && expense.date.month() <= current_month){
                    expenses += expense.amount;
                }
            }

            budget::money earnings;
            for(auto& earning : all_earnings()){
                if(earning.date.year() == current_year && earning.date.month() >= sm && earning.date.month() <= current_month){
                    earnings += earning.amount;
                }
            }

            auto balance = earnings - expenses;
            for(unsigned short i = sm; i <= current_month; ++i){
                boost::gregorian::greg_month month = i;

                auto current_accounts = all_accounts(current_year, month);

                for(auto& c : current_accounts){
                    balance += c.amount;
                }
            }

            for(auto& objective : objectives.data){
                if(objective.type == "yearly"){
                    std::cout << "  ";
                    print_minimum(objective.name, width);
                    std::cout << "  ";

                    print_success(balance, earnings, expenses, objective);

                    std::cout << std::endl;
                }
            }

            if(monthly){
                std::cout << std::endl;
            }
        }

        if(monthly){
            std::cout << "Month objectives" << std::endl;

            size_t width = 0;
            for(unsigned short i = sm; i <= current_month; ++i){
                boost::gregorian::greg_month month = i;

                std::stringstream stream;
                stream << month;

                width = std::max(width, stream.str().size());
            }

            for(auto& objective : objectives.data){
                if(objective.type == "monthly"){
                    std::cout << std::endl << objective.name << std::endl;

                    size_t width = 0;
                    for(unsigned short i = sm; i <= current_month; ++i){
                        boost::gregorian::greg_month month = i;

                        std::cout << "  ";
                        print_minimum(month, width);
                        std::cout << "  ";

                        budget::money expenses;
                        for(auto& expense : all_expenses()){
                            if(expense.date.year() == current_year && expense.date.month() == month){
                                expenses += expense.amount;
                            }
                        }

                        budget::money earnings;
                        for(auto& earning : all_earnings()){
                            if(earning.date.year() == current_year && earning.date.month() == month){
                                earnings += earning.amount;
                            }
                        }

                        auto balance = earnings - expenses;
                        for(auto& c : all_accounts(current_year, month)){
                            balance += c.amount;
                        }

                        print_success(balance, earnings, expenses, objective);

                        std::cout << std::endl;
                    }
                }
            }
        }
    }
}

} //end of anonymous namespace

void budget::objectives_module::load(){
    load_expenses();
    load_earnings();
    load_accounts();
    load_fortunes();
    load_objectives();
}

void budget::objectives_module::unload(){
    save_objectives();
}

void budget::objectives_module::handle(const std::vector<std::string>& args){
    if(args.size() == 1){
        status_objectives();
    } else {
        auto& subcommand = args[1];

        if(subcommand == "list"){
            list_objectives();
        } else if(subcommand == "status"){
            status_objectives();
        } else if(subcommand == "add"){
            objective objective;
            objective.guid = generate_guid();
            objective.date = boost::gregorian::day_clock::local_day();

            edit_string(objective.name, "Name");
            not_empty(objective.name, "The name of the objective cannot be empty");

            edit_string(objective.type, "Type");
            not_empty(objective.type, "The type of the objective cannot be empty");

            edit_string(objective.source, "Source");
            not_empty(objective.source, "The source of the objective cannot be empty");

            edit_string(objective.op, "Operator");
            not_empty(objective.op, "The operator of the objective cannot be empty");

            edit_money(objective.amount, "Amount");

            add_data(objectives, std::move(objective));
        } else if(subcommand == "delete"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(objectives, id)){
                throw budget_exception("There are no objective with id ");
            }

            remove(objectives, id);

            std::cout << "Objective " << id << " has been deleted" << std::endl;
        } else if(subcommand == "edit"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(objectives, id)){
                throw budget_exception("There are no objective with id " + args[2]);
            }

            auto& objective = get(objectives, id);

            edit_string(objective.name, "Name");
            not_empty(objective.name, "The name of the objective cannot be empty");

            edit_string(objective.type, "Type");
            not_empty(objective.type, "The type of the objective cannot be empty");

            edit_string(objective.source, "Source");
            not_empty(objective.source, "The source of the objective cannot be empty");

            edit_string(objective.op, "Operator");
            not_empty(objective.op, "The operator of the objective cannot be empty");

            edit_money(objective.amount, "Amount");

            set_objectives_changed();
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}

void budget::load_objectives(){
    load_data(objectives, "objectives.data");
}

void budget::save_objectives(){
    save_data(objectives, "objectives.data");
}

void budget::add_objective(budget::objective&& objective){
    add_data(objectives, std::forward<budget::objective>(objective));
}

std::ostream& budget::operator<<(std::ostream& stream, const objective& objective){
    return stream
        << objective.id  << ':'
        << objective.guid << ':'
        << objective.name << ':'
        << objective.type << ':'
        << objective.source << ':'
        << objective.op << ':'
        << objective.amount << ':'
        << to_string(objective.date);
}

void budget::operator>>(const std::vector<std::string>& parts, objective& objective){
    objective.id = to_number<std::size_t>(parts[0]);
    objective.guid = parts[1];
    objective.name = parts[2];
    objective.type = parts[3];
    objective.source = parts[4];
    objective.op = parts[5];
    objective.amount = parse_money(parts[6]);
    objective.date = boost::gregorian::from_string(parts[7]);
}

std::vector<objective>& budget::all_objectives(){
    return objectives.data;
}

void budget::set_objectives_changed(){
    objectives.changed = true;
}
<commit_msg>Tune colors<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

#include "objectives.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "fortune.hpp"
#include "accounts.hpp"
#include "args.hpp"
#include "data.hpp"
#include "guid.hpp"
#include "config.hpp"
#include "utils.hpp"
#include "console.hpp"
#include "budget_exception.hpp"

using namespace budget;

namespace {

static data_handler<objective> objectives;

void list_objectives(){
    if(objectives.data.size() == 0){
        std::cout << "No objectives" << std::endl;
    } else {
        std::vector<std::string> columns = {"ID", "Name", "Type", "Source", "Operator", "Amount"};
        std::vector<std::vector<std::string>> contents;

        for(auto& objective : objectives.data){
            contents.push_back({to_string(objective.id), objective.name, objective.type, objective.source, objective.op, to_string(objective.amount)});
        }

        display_table(columns, contents);
    }
}

template<typename T>
void print_minimum(const T& str, std::size_t min_width){
    auto old_width = std::cout.width();
    std::cout.width(min_width);
    std::cout << str;
    std::cout.width(old_width);
}

void print_success(budget::money balance, budget::money earnings, budget::money expenses, const budget::objective& objective){
    auto amount = objective.amount;

    budget::money basis;
    if(objective.source == "expenses"){
        basis = expenses;
    } else if (objective.source == "earnings") {
        basis = earnings;
    } else {
        basis = balance;
    }

    int success = 0;
    if(objective.op == "min"){
        auto percent = basis.dollars() / static_cast<double>(amount.dollars());
        success = percent * 100;
    } else if(objective.op == "max"){
        auto percent = amount.dollars() / static_cast<double>(basis.dollars());
        success = percent * 100;
    }

    success = std::max(0, success);

    if(success < 25){
        std::cout << "\033[0;31m";
    } else if(success < 75){
        std::cout << "\033[0;33m";
    } else if(success < 100){
        std::cout << "\033[0;32m";
    } else if(success >= 100){
        std::cout << "\033[1;32m";
    }

    print_minimum(success, 5);
    std::cout << "%\033[0m  ";

    success = std::min(success, 109);
    auto good = success == 0 ? 0 : (success / 10) + 1;

    for(std::size_t i = 0; i < good; ++i){
        std::cout << "\033[1;42m   \033[0m";
    }

    for(std::size_t i = good; i < 11; ++i){
        std::cout << "\033[1;41m   \033[0m";
    }
}

void status_objectives(){
    if(objectives.data.size() == 0){
        std::cout << "No objectives" << std::endl;
    } else {
        auto today = boost::gregorian::day_clock::local_day();
        auto current_month = today.month();
        auto current_year = today.year();
        auto sm = start_month(current_year);

        size_t monthly = 0;
        size_t yearly = 0;

        for(auto& objective : objectives.data){
            if(objective.type == "yearly"){
                ++yearly;
            } else if(objective.type == "monthly"){
                ++monthly;
            }
        }

        if(yearly){
            std::cout << "Year objectives" << std::endl << std::endl;

            size_t width = 0;
            for(auto& objective : objectives.data){
                if(objective.type == "yearly"){
                    width = std::max(rsize(objective.name), width);
                }
            }

            budget::money expenses;
            for(auto& expense : all_expenses()){
                if(expense.date.year() == current_year && expense.date.month() >= sm && expense.date.month() <= current_month){
                    expenses += expense.amount;
                }
            }

            budget::money earnings;
            for(auto& earning : all_earnings()){
                if(earning.date.year() == current_year && earning.date.month() >= sm && earning.date.month() <= current_month){
                    earnings += earning.amount;
                }
            }

            auto balance = earnings - expenses;
            for(unsigned short i = sm; i <= current_month; ++i){
                boost::gregorian::greg_month month = i;

                auto current_accounts = all_accounts(current_year, month);

                for(auto& c : current_accounts){
                    balance += c.amount;
                }
            }

            for(auto& objective : objectives.data){
                if(objective.type == "yearly"){
                    std::cout << "  ";
                    print_minimum(objective.name, width);
                    std::cout << "  ";

                    print_success(balance, earnings, expenses, objective);

                    std::cout << std::endl;
                }
            }

            if(monthly){
                std::cout << std::endl;
            }
        }

        if(monthly){
            std::cout << "Month objectives" << std::endl;

            size_t width = 0;
            for(unsigned short i = sm; i <= current_month; ++i){
                boost::gregorian::greg_month month = i;

                std::stringstream stream;
                stream << month;

                width = std::max(width, stream.str().size());
            }

            for(auto& objective : objectives.data){
                if(objective.type == "monthly"){
                    std::cout << std::endl << objective.name << std::endl;

                    size_t width = 0;
                    for(unsigned short i = sm; i <= current_month; ++i){
                        boost::gregorian::greg_month month = i;

                        std::cout << "  ";
                        print_minimum(month, width);
                        std::cout << "  ";

                        budget::money expenses;
                        for(auto& expense : all_expenses()){
                            if(expense.date.year() == current_year && expense.date.month() == month){
                                expenses += expense.amount;
                            }
                        }

                        budget::money earnings;
                        for(auto& earning : all_earnings()){
                            if(earning.date.year() == current_year && earning.date.month() == month){
                                earnings += earning.amount;
                            }
                        }

                        auto balance = earnings - expenses;
                        for(auto& c : all_accounts(current_year, month)){
                            balance += c.amount;
                        }

                        print_success(balance, earnings, expenses, objective);

                        std::cout << std::endl;
                    }
                }
            }
        }
    }
}

} //end of anonymous namespace

void budget::objectives_module::load(){
    load_expenses();
    load_earnings();
    load_accounts();
    load_fortunes();
    load_objectives();
}

void budget::objectives_module::unload(){
    save_objectives();
}

void budget::objectives_module::handle(const std::vector<std::string>& args){
    if(args.size() == 1){
        status_objectives();
    } else {
        auto& subcommand = args[1];

        if(subcommand == "list"){
            list_objectives();
        } else if(subcommand == "status"){
            status_objectives();
        } else if(subcommand == "add"){
            objective objective;
            objective.guid = generate_guid();
            objective.date = boost::gregorian::day_clock::local_day();

            edit_string(objective.name, "Name");
            not_empty(objective.name, "The name of the objective cannot be empty");

            edit_string(objective.type, "Type");
            not_empty(objective.type, "The type of the objective cannot be empty");

            edit_string(objective.source, "Source");
            not_empty(objective.source, "The source of the objective cannot be empty");

            edit_string(objective.op, "Operator");
            not_empty(objective.op, "The operator of the objective cannot be empty");

            edit_money(objective.amount, "Amount");

            add_data(objectives, std::move(objective));
        } else if(subcommand == "delete"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(objectives, id)){
                throw budget_exception("There are no objective with id ");
            }

            remove(objectives, id);

            std::cout << "Objective " << id << " has been deleted" << std::endl;
        } else if(subcommand == "edit"){
            enough_args(args, 3);

            std::size_t id = to_number<std::size_t>(args[2]);

            if(!exists(objectives, id)){
                throw budget_exception("There are no objective with id " + args[2]);
            }

            auto& objective = get(objectives, id);

            edit_string(objective.name, "Name");
            not_empty(objective.name, "The name of the objective cannot be empty");

            edit_string(objective.type, "Type");
            not_empty(objective.type, "The type of the objective cannot be empty");

            edit_string(objective.source, "Source");
            not_empty(objective.source, "The source of the objective cannot be empty");

            edit_string(objective.op, "Operator");
            not_empty(objective.op, "The operator of the objective cannot be empty");

            edit_money(objective.amount, "Amount");

            set_objectives_changed();
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}

void budget::load_objectives(){
    load_data(objectives, "objectives.data");
}

void budget::save_objectives(){
    save_data(objectives, "objectives.data");
}

void budget::add_objective(budget::objective&& objective){
    add_data(objectives, std::forward<budget::objective>(objective));
}

std::ostream& budget::operator<<(std::ostream& stream, const objective& objective){
    return stream
        << objective.id  << ':'
        << objective.guid << ':'
        << objective.name << ':'
        << objective.type << ':'
        << objective.source << ':'
        << objective.op << ':'
        << objective.amount << ':'
        << to_string(objective.date);
}

void budget::operator>>(const std::vector<std::string>& parts, objective& objective){
    objective.id = to_number<std::size_t>(parts[0]);
    objective.guid = parts[1];
    objective.name = parts[2];
    objective.type = parts[3];
    objective.source = parts[4];
    objective.op = parts[5];
    objective.amount = parse_money(parts[6]);
    objective.date = boost::gregorian::from_string(parts[7]);
}

std::vector<objective>& budget::all_objectives(){
    return objectives.data;
}

void budget::set_objectives_changed(){
    objectives.changed = true;
}
<|endoftext|>


<commit_before>/**
 * @file llsecondlifeurls.cpp
 * @brief Urls used in the product
 *
 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"
#include "llsecondlifeurls.h"
/*
const std::string CREATE_ACCOUNT_URL (
	"http://join.secondlife.com/");

const std::string MANAGE_ACCOUNT (
	"http://secondlife.com/account/");  // *TODO: NOT USED

const std::string AUCTION_URL (
	"http://secondlife.com/auctions/auction-detail.php?id=");

const std::string EVENTS_URL (
	"http://secondlife.com/events/");
*/
const std::string TIER_UP_URL (
	"http://secondlife.com/app/landtier"); // *TODO: Translate (simulator)

const std::string DIRECTX_9_URL (
								 "http://secondlife.com/support/"); // *TODO: NOT USED
/*
const std::string LAND_URL (
	"http://secondlife.com/app/landtier"); // *TODO: NOT USED

const std::string UPGRADE_TO_PREMIUM_URL (
	"http://secondlife.com/app/upgrade/"); // *TODO: NOT USED

const std::string AMD_AGP_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string VIA_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string SUPPORT_URL (
    "http://secondlife.com/support/");

const std::string INTEL_CHIPSET_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string SIS_CHIPSET_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string BLOGS_URL (
	"http://blog.secondlife.com/"); // *TODO: NOT USED

const std::string BUY_CURRENCY_URL (
	"http://secondlife.com/app/currency/");

const std::string LSL_DOC_URL (
	"http://secondlife.com/app/lsldoc/");  // *TODO: NOT USED

const std::string SL_KB_URL (
	"http://secondlife.com/knowledgebase/"); // *TODO: NOT USED

const std::string RELEASE_NOTES_BASE_URL (
	"http://wiki.phoenixviewer.com/doku.php?id=firestorm_change_log");
*/

<commit_msg>Updated Firestorm change log URL in llsecondlifeurls.cpp to new URL format<commit_after>/**
 * @file llsecondlifeurls.cpp
 * @brief Urls used in the product
 *
 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"
#include "llsecondlifeurls.h"
/*
const std::string CREATE_ACCOUNT_URL (
	"http://join.secondlife.com/");

const std::string MANAGE_ACCOUNT (
	"http://secondlife.com/account/");  // *TODO: NOT USED

const std::string AUCTION_URL (
	"http://secondlife.com/auctions/auction-detail.php?id=");

const std::string EVENTS_URL (
	"http://secondlife.com/events/");
*/
const std::string TIER_UP_URL (
	"http://secondlife.com/app/landtier"); // *TODO: Translate (simulator)

const std::string DIRECTX_9_URL (
								 "http://secondlife.com/support/"); // *TODO: NOT USED
/*
const std::string LAND_URL (
	"http://secondlife.com/app/landtier"); // *TODO: NOT USED

const std::string UPGRADE_TO_PREMIUM_URL (
	"http://secondlife.com/app/upgrade/"); // *TODO: NOT USED

const std::string AMD_AGP_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string VIA_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string SUPPORT_URL (
    "http://secondlife.com/support/");

const std::string INTEL_CHIPSET_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string SIS_CHIPSET_URL (
	"http://secondlife.com/support/"); // *TODO: NOT USED

const std::string BLOGS_URL (
	"http://blog.secondlife.com/"); // *TODO: NOT USED

const std::string BUY_CURRENCY_URL (
	"http://secondlife.com/app/currency/");

const std::string LSL_DOC_URL (
	"http://secondlife.com/app/lsldoc/");  // *TODO: NOT USED

const std::string SL_KB_URL (
	"http://secondlife.com/knowledgebase/"); // *TODO: NOT USED

const std::string RELEASE_NOTES_BASE_URL (
	"http://wiki.phoenixviewer.com/firestorm_change_log");
*/

<|endoftext|>


<commit_before>/**
 * @file
 * @author lpraz
 *
 * @section DESCRIPTION
 * Defines tiger's operations functions, which are the top-level functions
 * for each of tiger's commands.
 * Any operations functions will be placed in the Tiger::Operations
 * namespace.
 */

// Stdlib includes
#include <iostream>

// Include own header
#include "operations.hpp"

namespace Tiger {
    namespace Operations {
        /**
         * Displays a list of all files with given tags, and all tags
         * attached to given files.
         * Called by the user with the "search" command.
         *
         * @param tags The hash table of tags to search through.
         * @param command The command object containing the arguments
         *                to base the search on.
         */
        void search(std::unordered_map<std::string,
                std::vector<std::string>> tags, Tiger::Command command) {
            std::cout << "=== Tags ===\n";
            for (auto iter : command.getTags()) {
               std::cout << iter << ":\n";
            }

            std::cout << "=== Files ===\n";
            for (auto iter : command.getFiles()) {

            }
        }

        /**
         * Displays a list of all tags, and all files that have those
         * tags.
         * Called by the user with the "list" command.
         *
         * @param tags The hash table of tags to output.
         */
        void displayListOfTags(std::unordered_map<std::string,
                std::vector<std::string>> tags) {
            for (auto tag : tags) {
                std::cout << tag.first << ":\n\t";

                for (auto file = tag.second.begin();
                        file != tag.second.end(); file++) {
                    if (file != tag.second.begin())
                        std::cout << ",\n";

                    std::cout << *file;
                }

                std::cout << std::endl;
            }
        }

        /**
         * Displays the help for the application and its commands.
         * Called by the user with the "help" command, or by specifying
         * no command at all.
         */
        void displayHelp(void) {
            std::string helpText =
                    "tiger is a program for tagging and organizing files.\n"
                    "Commands:\n"
                    "    help: Display this screen.\n"
                    "    tag: Add a tag to a file.\n"
                    "    search: Look up files with a certain tag.\n"
                    "    list: Display all tags on your system, and all\n"
                    "          of the files they are attached to.\n";

            std::cout << helpText;
        }
    }
}
<commit_msg>Finished search method, for now<commit_after>/**
 * @file
 * @author lpraz
 *
 * @section DESCRIPTION
 * Defines tiger's operations functions, which are the top-level functions
 * for each of tiger's commands.
 * Any operations functions will be placed in the Tiger::Operations
 * namespace.
 */

// Stdlib includes
#include <algorithm>
#include <iostream>

// Include own header
#include "operations.hpp"

namespace Tiger {
    namespace Operations {
        /**
         * Displays a list of all files with given tags, and all tags
         * attached to given files.
         * Called by the user with the "search" command.
         *
         * @param tags The hash table of tags to search through.
         * @param command The command object containing the arguments
         *                to base the search on.
         */
        void search(std::unordered_map<std::string,
                std::vector<std::string>> tags, Tiger::Command command) {
            std::cout << "=== Tags ===\n";
            for (auto tag : command.getTags()) {
                std::cout << tag << ":\n\t";

                auto tagFiles = tags.find(tag);
                if (tagFiles != tags.end()) {
                    for (auto tagFile = tagFiles->second.begin();
                            tagFile != tagFiles->second.end(); tagFile++) {
                        if (tagFile != tagFiles->second.begin())
                            std::cout << ",\n\t";

                        std::cout << *tagFile;
                    }
                }
            }

            std::cout << "=== Files ===\n";
            for (auto file : command.getFiles()) {
                std::cout << file << ":\n\t";

                bool first = true;
                for (auto tag : tags) {
                    if (std::find(tag.second.begin(), tag.second.end(),
                            file) != tag.second.end()) {
                        if (first)
                            first = false;
                        else
                            std::cout << ",\n\t";

                        std::cout << tag.first;
                    }
                }
            }
        }

        /**
         * Displays a list of all tags, and all files that have those
         * tags.
         * Called by the user with the "list" command.
         *
         * @param tags The hash table of tags to output.
         */
        void displayListOfTags(std::unordered_map<std::string,
                std::vector<std::string>> tags) {
            for (auto tag : tags) {
                std::cout << tag.first << ":\n\t";

                for (auto file = tag.second.begin();
                        file != tag.second.end(); file++) {
                    if (file != tag.second.begin())
                        std::cout << ",\n\t";

                    std::cout << *file;
                }

                std::cout << std::endl;
            }
        }

        /**
         * Displays the help for the application and its commands.
         * Called by the user with the "help" command, or by specifying
         * no command at all.
         */
        void displayHelp(void) {
            std::string helpText =
                    "tiger is a program for tagging and organizing files.\n"
                    "Commands:\n"
                    "    help: Display this screen.\n"
                    "    tag: Add a tag to a file.\n"
                    "    search: Look up files with a certain tag.\n"
                    "    list: Display all tags on your system, and all\n"
                    "          of the files they are attached to.\n";

            std::cout << helpText;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2021 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 <outputtype.h>

#include <pubkey.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <util/vector.h>

#include <assert.h>
#include <optional>
#include <string>

static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
static const std::string OUTPUT_TYPE_STRING_BECH32M = "bech32m";

std::optional<OutputType> ParseOutputType(const std::string& type)
{
    if (type == OUTPUT_TYPE_STRING_LEGACY) {
        return OutputType::LEGACY;
    } else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) {
        return OutputType::P2SH_SEGWIT;
    } else if (type == OUTPUT_TYPE_STRING_BECH32) {
        return OutputType::BECH32;
    } else if (type == OUTPUT_TYPE_STRING_BECH32M) {
        return OutputType::BECH32M;
    }
    return std::nullopt;
}

const std::string& FormatOutputType(OutputType type)
{
    switch (type) {
    case OutputType::LEGACY: return OUTPUT_TYPE_STRING_LEGACY;
    case OutputType::P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT;
    case OutputType::BECH32: return OUTPUT_TYPE_STRING_BECH32;
    case OutputType::BECH32M: return OUTPUT_TYPE_STRING_BECH32M;
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
{
    switch (type) {
    case OutputType::LEGACY: return PKHash(key);
    case OutputType::P2SH_SEGWIT:
    case OutputType::BECH32: {
        if (!key.IsCompressed()) return PKHash(key);
        CTxDestination witdest = WitnessV0KeyHash(key);
        CScript witprog = GetScriptForDestination(witdest);
        if (type == OutputType::P2SH_SEGWIT) {
            return ScriptHash(witprog);
        } else {
            return witdest;
        }
    }
    case OutputType::BECH32M: {} // This function should never be used with BECH32M, so let it assert
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
{
    PKHash keyid(key);
    CTxDestination p2pkh{keyid};
    if (key.IsCompressed()) {
        CTxDestination segwit = WitnessV0KeyHash(keyid);
        CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
        return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));
    } else {
        return Vector(std::move(p2pkh));
    }
}

CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type)
{
    // Add script to keystore
    keystore.AddCScript(script);
    // Note that scripts over 520 bytes are not yet supported.
    switch (type) {
    case OutputType::LEGACY:
        return ScriptHash(script);
    case OutputType::P2SH_SEGWIT:
    case OutputType::BECH32: {
        CTxDestination witdest = WitnessV0ScriptHash(script);
        CScript witprog = GetScriptForDestination(witdest);
        // Check if the resulting program is solvable (i.e. doesn't use an uncompressed key)
        if (!IsSolvable(keystore, witprog)) return ScriptHash(script);
        // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
        keystore.AddCScript(witprog);
        if (type == OutputType::BECH32) {
            return witdest;
        } else {
            return ScriptHash(witprog);
        }
    }
    case OutputType::BECH32M: {} // This function should not be used for BECH32M, so let it assert
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) {
    if (std::holds_alternative<PKHash>(dest) ||
        std::holds_alternative<ScriptHash>(dest)) {
        return OutputType::LEGACY;
    }
    if (std::holds_alternative<WitnessV0KeyHash>(dest) ||
        std::holds_alternative<WitnessV0ScriptHash>(dest)) {
        return OutputType::BECH32;
    }
    if (std::holds_alternative<WitnessV1Taproot>(dest) ||
        std::holds_alternative<WitnessUnknown>(dest)) {
        return OutputType::BECH32M;
    }
    return std::nullopt;
}
<commit_msg>outputtype: remove redundant check for uncompressed keys in AddAndGetDestinationForScript<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2021 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 <outputtype.h>

#include <pubkey.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <util/vector.h>

#include <assert.h>
#include <optional>
#include <string>

static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
static const std::string OUTPUT_TYPE_STRING_BECH32M = "bech32m";

std::optional<OutputType> ParseOutputType(const std::string& type)
{
    if (type == OUTPUT_TYPE_STRING_LEGACY) {
        return OutputType::LEGACY;
    } else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) {
        return OutputType::P2SH_SEGWIT;
    } else if (type == OUTPUT_TYPE_STRING_BECH32) {
        return OutputType::BECH32;
    } else if (type == OUTPUT_TYPE_STRING_BECH32M) {
        return OutputType::BECH32M;
    }
    return std::nullopt;
}

const std::string& FormatOutputType(OutputType type)
{
    switch (type) {
    case OutputType::LEGACY: return OUTPUT_TYPE_STRING_LEGACY;
    case OutputType::P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT;
    case OutputType::BECH32: return OUTPUT_TYPE_STRING_BECH32;
    case OutputType::BECH32M: return OUTPUT_TYPE_STRING_BECH32M;
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
{
    switch (type) {
    case OutputType::LEGACY: return PKHash(key);
    case OutputType::P2SH_SEGWIT:
    case OutputType::BECH32: {
        if (!key.IsCompressed()) return PKHash(key);
        CTxDestination witdest = WitnessV0KeyHash(key);
        CScript witprog = GetScriptForDestination(witdest);
        if (type == OutputType::P2SH_SEGWIT) {
            return ScriptHash(witprog);
        } else {
            return witdest;
        }
    }
    case OutputType::BECH32M: {} // This function should never be used with BECH32M, so let it assert
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
{
    PKHash keyid(key);
    CTxDestination p2pkh{keyid};
    if (key.IsCompressed()) {
        CTxDestination segwit = WitnessV0KeyHash(keyid);
        CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
        return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));
    } else {
        return Vector(std::move(p2pkh));
    }
}

CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type)
{
    // Add script to keystore
    keystore.AddCScript(script);
    // Note that scripts over 520 bytes are not yet supported.
    switch (type) {
    case OutputType::LEGACY:
        return ScriptHash(script);
    case OutputType::P2SH_SEGWIT:
    case OutputType::BECH32: {
        CTxDestination witdest = WitnessV0ScriptHash(script);
        CScript witprog = GetScriptForDestination(witdest);
        // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
        keystore.AddCScript(witprog);
        if (type == OutputType::BECH32) {
            return witdest;
        } else {
            return ScriptHash(witprog);
        }
    }
    case OutputType::BECH32M: {} // This function should not be used for BECH32M, so let it assert
    } // no default case, so the compiler can warn about missing cases
    assert(false);
}

std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) {
    if (std::holds_alternative<PKHash>(dest) ||
        std::holds_alternative<ScriptHash>(dest)) {
        return OutputType::LEGACY;
    }
    if (std::holds_alternative<WitnessV0KeyHash>(dest) ||
        std::holds_alternative<WitnessV0ScriptHash>(dest)) {
        return OutputType::BECH32;
    }
    if (std::holds_alternative<WitnessV1Taproot>(dest) ||
        std::holds_alternative<WitnessUnknown>(dest)) {
        return OutputType::BECH32M;
    }
    return std::nullopt;
}
<|endoftext|>


<commit_before>#include "../include/AnimatedSprite.h"
#include "../include/GameWindow.h"

AnimatedSprite::AnimatedSprite(Texture* sheet, int rows, int cols, float speed, bool loop)
{
    m_material = new Material(sheet);
	m_loop = loop;
	m_cols = cols;
	m_rows = rows;
	m_speed = speed;
	m_index = 0;
	m_clock.Start();

#ifdef MODERN_OPENGL
    m_shader = new Shader();
    m_shader->fromString(default_vert, default_frag);

    m_shader->compile();
    m_shader->addCommonUniforms();
    m_shader->addUniform("diffuse");
    if (m_material->getNormalTexture() != NULL)
        m_shader->addUniform("normal");
    m_shader->addUniform("cliprect");
    m_shader->addUniform("u_lightPos");
    m_shader->addUniform("u_lightColor");
    m_shader->addUniform("u_lightIntens");
    m_shader->addUniform("u_ambientColor");
    m_shader->addUniform("m_specularPower");
    m_shader->addUniform("m_normalPower");
    m_shader->addUniform("m_diffuseColor");
    m_shader->addUniform("m_specularColor");
#endif
}

AnimatedSprite::AnimatedSprite(Texture *sheet, Texture *sheet_norm, int rows, int cols, float speed, bool loop)
{
    m_material = new Material(sheet, sheet_norm);
    m_loop = loop;
    m_cols = cols;
    m_rows = rows;
    m_speed = speed;
    m_index = 0;
    m_clock.Start();

#ifdef MODERN_OPENGL
    m_shader = new Shader();
    m_shader->fromString(default_vert, default_frag);

    m_shader->compile();
    m_shader->addCommonUniforms();
    m_shader->addUniform("diffuse");
    if (m_material->getNormalTexture() != NULL)
        m_shader->addUniform("normal");
    m_shader->addUniform("cliprect");
    m_shader->addUniform("u_lightPos");
    m_shader->addUniform("u_lightColor");
    m_shader->addUniform("u_lightIntens");
    m_shader->addUniform("u_ambientColor");
    m_shader->addUniform("m_specularPower");
    m_shader->addUniform("m_normalPower");
    m_shader->addUniform("m_diffuseColor");
    m_shader->addUniform("m_specularColor");
#endif
}

AnimatedSprite::~AnimatedSprite()
{
    SAFE_DELETE(m_material);
	SAFE_DELETE(m_shader);
}

void AnimatedSprite::step()
{
	if (m_index < 0) m_index = 0;
    if (m_material == NULL) return;
	if (m_cols <= 0 || m_rows <= 0) return;

	int fc = m_rows * m_cols;
	if (m_clock.ElapsedMillis() >= (int)(1000.0f * m_speed))
	{
		m_clock.Restart();
		if (m_index++ >= fc - 1)
		{
			if (m_loop)
				m_index = 0;
			else
				m_index = fc - 1;
		}
	}
	int i = 0;
	i = m_index;

    int w = m_material->getDiffuseTexture()->getResource()->getWidth() / m_cols;
    int h = m_material->getDiffuseTexture()->getResource()->getHeight() / m_rows;

	int ax = i % m_cols * w;
	int ay = (int)(i / m_cols) * h;

	rect clip;
	clip.x = ax;
	clip.y = ay;
	clip.w = w;
	clip.h = h;
	clip.frame = i;
	clip.cols = m_cols;
	clip.rows = m_rows;
    m_material->getDiffuseTexture()->setCliprect(clip);
    if (m_material->getNormalTexture() != NULL)
        m_material->getNormalTexture()->setCliprect(clip);
}

void AnimatedSprite::draw(SceneTree* tree)
{
    if (!m_material) return;

    m_material->getDiffuseTexture()->use(0);
    if (m_material->getNormalTexture() != NULL)
        m_material->getNormalTexture()->use(1);

    vec4 tr = m_material->getDiffuseTexture()->getTransformedClipRect();

#ifdef MODERN_OPENGL
    std::vector<Light*> lights = tree->getLights();
    if (m_shader != nullptr)
    {
        m_shader->use();
        m_shader->setInt("diffuse", 0);
        m_shader->setVec4("cliprect", tr.x, tr.y, tr.z, tr.w);
        m_shader->setMatrix("model", getTransform()->getTransformation());
        m_shader->setMatrix("proj", GameWindow::Projection);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        if (m_material->getIsSshadeless())
        {
            m_shader->setVec4("u_ambientColor", 1.0f, 1.0f, 1.0f, 1.0f);
            m_material->getDiffuseTexture()->getShape()->draw(GL_TRIANGLE_STRIP);
        }
        else
        {
            if (m_material->getNormalTexture() != NULL)
                m_shader->setInt("normal", 1);

            m_shader->setFloat("m_specularPower", m_material->getSpecularPower());
            m_shader->setFloat("m_normalPower", m_material->getNormalPower());
            m_shader->setVec4("m_diffuseColor", m_material->dR,
                                                m_material->dG,
                                                m_material->dB,
                                                m_material->dA);
            m_shader->setVec4("m_specularColor", m_material->sR,
                                                 m_material->sG,
                                                 m_material->sB,
                                                 m_material->sA);
            Color ambient = tree->getEngine()->getAmbient();
            m_shader->setVec4("u_ambientColor", ambient.r, ambient.g, ambient.b, ambient.a);

            if (lights.size() > 0)
            {

                glBlendFunc(GL_ONE, GL_ONE);
                glBlendEquation(GL_FUNC_ADD);

                for (Light*& l : lights)
                {
                    Vector3 lpos = l->getTransform()->getTranslation();
                    Color lcol = l->getColor();
                    m_shader->setVec3("u_lightPos", lpos.x, lpos.y, lpos.z);
                    m_shader->setVec4("u_lightColor", lcol.r, lcol.g, lcol.b, lcol.a);
                    m_shader->setFloat("u_lightIntens", l->getIntensity());

                    m_material->getDiffuseTexture()->getShape()->draw(GL_TRIANGLE_STRIP);
                }
            }
            else
            {
                m_material->getDiffuseTexture()->getShape()->draw(GL_TRIANGLE_STRIP);
            }
        }
        glDisable(GL_BLEND);
    }

    glUseProgram(0);
#endif
}

void AnimatedSprite::update(float delta)
{
	Node::update(delta);
    step();
}

bool AnimatedSprite::hovered(point mousepos)
{
    if (!m_material) return false;

    Vector3 pos = getTransform()->getTranslation();
    float w = (float)m_material->getDiffuseTexture()->getWidth();
    float h = (float)m_material->getDiffuseTexture()->getHeight();
    float sradius = w < h ? w / 2.0f : h / 2.0f;

    return (collisiondetection::circle(mousepos.x, mousepos.y, 2, pos.x, pos.y, sradius));
}

Material *AnimatedSprite::getMaterial() const
{
    return m_material;
}

void AnimatedSprite::setMaterial(Material *material)
{
    m_material = material;
}

void AnimatedSprite::RegisterObject(lua_State* L)
{
	using namespace luabridge;

	getGlobalNamespace(L)
		.beginClass<AnimatedSprite>("AnimatedSprite")
		.addConstructor<void(*)(Texture*, int, int, float, bool)>()
		.addProperty("rows", &AnimatedSprite::getRows, &AnimatedSprite::setRows)
		.addProperty("columns", &AnimatedSprite::getCols, &AnimatedSprite::setCols)
		.addProperty("speed", &AnimatedSprite::getSpeed, &AnimatedSprite::setSpeed)
		.addProperty("loop", &AnimatedSprite::getLoop, &AnimatedSprite::setLoop)
		.addProperty("index", &AnimatedSprite::getIndex)
		.addFunction("step", &AnimatedSprite::step)
		.endClass();
}
<commit_msg>Little things...<commit_after>#include "../include/AnimatedSprite.h"
#include "../include/GameWindow.h"

AnimatedSprite::AnimatedSprite(Texture* sheet, int rows, int cols, float speed, bool loop)
{
    m_material = new Material(sheet);
	m_loop = loop;
	m_cols = cols;
	m_rows = rows;
	m_speed = speed;
	m_index = 0;
	m_clock.Start();

#ifdef MODERN_OPENGL
    m_shader = new Shader();
    m_shader->fromString(default_vert, default_frag);

    m_shader->compile();
    m_shader->addCommonUniforms();
    m_shader->addUniform("diffuse");
    if (m_material->getNormalTexture() != NULL)
        m_shader->addUniform("normal");
    m_shader->addUniform("cliprect");
    m_shader->addUniform("u_lightPos");
    m_shader->addUniform("u_lightColor");
    m_shader->addUniform("u_lightIntens");
    m_shader->addUniform("u_ambientColor");
    m_shader->addUniform("m_specularPower");
    m_shader->addUniform("m_normalPower");
    m_shader->addUniform("m_diffuseColor");
    m_shader->addUniform("m_specularColor");
    m_shader->addUniform("u_lightFalloff");
#endif
}

AnimatedSprite::AnimatedSprite(Texture *sheet, Texture *sheet_norm, int rows, int cols, float speed, bool loop)
{
    m_material = new Material(sheet, sheet_norm);
    m_loop = loop;
    m_cols = cols;
    m_rows = rows;
    m_speed = speed;
    m_index = 0;
    m_clock.Start();

#ifdef MODERN_OPENGL
    m_shader = new Shader();
    m_shader->fromString(default_vert, default_frag);

    m_shader->compile();
    m_shader->addCommonUniforms();
    m_shader->addUniform("diffuse");
    if (m_material->getNormalTexture() != NULL)
        m_shader->addUniform("normal");
    m_shader->addUniform("cliprect");
    m_shader->addUniform("u_lightPos");
    m_shader->addUniform("u_lightColor");
    m_shader->addUniform("u_lightIntens");
    m_shader->addUniform("u_ambientColor");
    m_shader->addUniform("m_specularPower");
    m_shader->addUniform("m_normalPower");
    m_shader->addUniform("m_diffuseColor");
    m_shader->addUniform("m_specularColor");
    m_shader->addUniform("u_lightFalloff");
#endif
}

AnimatedSprite::~AnimatedSprite()
{
    SAFE_DELETE(m_material);
	SAFE_DELETE(m_shader);
}

void AnimatedSprite::step()
{
	if (m_index < 0) m_index = 0;
    if (m_material == NULL) return;
	if (m_cols <= 0 || m_rows <= 0) return;

	int fc = m_rows * m_cols;
	if (m_clock.ElapsedMillis() >= (int)(1000.0f * m_speed))
	{
		m_clock.Restart();
		if (m_index++ >= fc - 1)
		{
			if (m_loop)
				m_index = 0;
			else
				m_index = fc - 1;
		}
	}
	int i = 0;
	i = m_index;

    int w = m_material->getDiffuseTexture()->getResource()->getWidth() / m_cols;
    int h = m_material->getDiffuseTexture()->getResource()->getHeight() / m_rows;

	int ax = i % m_cols * w;
	int ay = (int)(i / m_cols) * h;

	rect clip;
	clip.x = ax;
	clip.y = ay;
	clip.w = w;
	clip.h = h;
	clip.frame = i;
	clip.cols = m_cols;
	clip.rows = m_rows;
    m_material->getDiffuseTexture()->setCliprect(clip);
    if (m_material->getNormalTexture() != NULL)
        m_material->getNormalTexture()->setCliprect(clip);
}

void AnimatedSprite::draw(SceneTree* tree)
{
    if (!m_material) return;

    m_material->getDiffuseTexture()->use(0);
    if (m_material->getNormalTexture() != NULL)
        m_material->getNormalTexture()->use(1);

    vec4 tr = m_material->getDiffuseTexture()->getTransformedClipRect();

#ifdef MODERN_OPENGL
    std::vector<Light*> lights = tree->getLights();
    if (m_shader != nullptr)
    {
        m_shader->use();
        m_shader->setInt("diffuse", 0);
        m_shader->setVec4("cliprect", tr.x, tr.y, tr.z, tr.w);
        m_shader->setMatrix("model", getTransform()->getTransformation());
        m_shader->setMatrix("proj", GameWindow::Projection);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        if (m_material->getIsSshadeless())
        {
            m_shader->setVec4("u_ambientColor", 1.0f, 1.0f, 1.0f, 1.0f);
            m_material->getDiffuseTexture()->getShape()->draw(GL_TRIANGLE_STRIP);
        }
        else
        {
            if (m_material->getNormalTexture() != NULL)
                m_shader->setInt("normal", 1);

            m_shader->setFloat("m_specularPower", m_material->getSpecularPower());
            m_shader->setFloat("m_normalPower", m_material->getNormalPower());
            m_shader->setVec4("m_diffuseColor", m_material->dR,
                                                m_material->dG,
                                                m_material->dB,
                                                m_material->dA);
            m_shader->setVec4("m_specularColor", m_material->sR,
                                                 m_material->sG,
                                                 m_material->sB,
                                                 m_material->sA);
            Color ambient = tree->getEngine()->getAmbient();
            m_shader->setVec4("u_ambientColor", ambient.r, ambient.g, ambient.b, ambient.a);

            if (lights.size() > 0)
            {

                glBlendFunc(GL_ONE, GL_ONE);
                glBlendEquation(GL_FUNC_ADD);

                for (Light*& l : lights)
                {
                    Vector3 lpos = l->getTransform()->getTranslation();
                    Color lcol = l->getColor();
                    m_shader->setVec3("u_lightPos", lpos.x, lpos.y, lpos.z);
                    m_shader->setVec4("u_lightColor", lcol.r, lcol.g, lcol.b, lcol.a);
                    m_shader->setFloat("u_lightIntens", l->getIntensity());
                    m_shader->setVec3("u_lightFalloff", l->getConstant(), l->getLinear(), l->getQuadratic());

                    m_material->getDiffuseTexture()->getShape()->draw(GL_TRIANGLE_STRIP);
                }
            }
            else
            {
                m_material->getDiffuseTexture()->getShape()->draw(GL_TRIANGLE_STRIP);
            }
        }
        glDisable(GL_BLEND);
    }

    glUseProgram(0);
#endif
}

void AnimatedSprite::update(float delta)
{
	Node::update(delta);
    step();
}

bool AnimatedSprite::hovered(point mousepos)
{
    if (!m_material) return false;

    Vector3 pos = getTransform()->getTranslation();
    float w = (float)m_material->getDiffuseTexture()->getWidth();
    float h = (float)m_material->getDiffuseTexture()->getHeight();
    float sradius = w < h ? w / 2.0f : h / 2.0f;

    return (collisiondetection::circle(mousepos.x, mousepos.y, 2, pos.x, pos.y, sradius));
}

Material *AnimatedSprite::getMaterial() const
{
    return m_material;
}

void AnimatedSprite::setMaterial(Material *material)
{
    m_material = material;
}

void AnimatedSprite::RegisterObject(lua_State* L)
{
	using namespace luabridge;

	getGlobalNamespace(L)
		.beginClass<AnimatedSprite>("AnimatedSprite")
		.addConstructor<void(*)(Texture*, int, int, float, bool)>()
		.addProperty("rows", &AnimatedSprite::getRows, &AnimatedSprite::setRows)
		.addProperty("columns", &AnimatedSprite::getCols, &AnimatedSprite::setCols)
		.addProperty("speed", &AnimatedSprite::getSpeed, &AnimatedSprite::setSpeed)
		.addProperty("loop", &AnimatedSprite::getLoop, &AnimatedSprite::setLoop)
		.addProperty("index", &AnimatedSprite::getIndex)
		.addFunction("step", &AnimatedSprite::step)
		.endClass();
}
<|endoftext|>