<commit_before>
#include "boost/asio.hpp"

#include "vtrc-application.h"
#include "vtrc-connection-list.h"

#include "vtrc-common/vtrc-enviroment.h"
#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-pool-pair.h"

namespace vtrc { namespace server {

    struct application::impl {

        common::enviroment                  env_;
        boost::asio::io_service            *ios_;
        const bool                          own_ios_;

        boost::asio::io_service            *rpc_ios_;
        const bool                          own_rpc_ios_;

        vtrc::shared_ptr<common::connection_list>   clients_;

        impl( )
            :ios_(new boost::asio::io_service)
            ,own_ios_(true)
            ,rpc_ios_(new boost::asio::io_service)
            ,own_rpc_ios_(true)
            ,clients_(common::connection_list::create( ))
        { }

        impl( boost::asio::io_service *ios )
            :ios_(ios)
            ,own_ios_(false)
            ,rpc_ios_(ios)
            ,own_rpc_ios_(false)
            ,clients_(common::connection_list::create( ))
        { }

        impl( boost::asio::io_service *ios, boost::asio::io_service *rpc_ios )
            :ios_(ios)
            ,own_ios_(false)
            ,rpc_ios_(rpc_ios)
            ,own_rpc_ios_(false)
            ,clients_(common::connection_list::create( ))
        { }

        static
        bool close_all_connection( common::connection_iface_sptr next )
        {
            next->close( );
            return true;
        }

        void stop_all_clients( )
        {
            clients_->foreach_while( close_all_connection );
        }

        ~impl( ) try
        {
            stop_all_clients( );
            clients_->clear( );

            if( own_ios_ )      delete ios_;
            if( own_rpc_ios_ )  delete rpc_ios_;

        } catch ( ... ) {

        }

        common::enviroment &get_enviroment( )
        {
            return env_;
        }

        boost::asio::io_service &get_io_service( )
        {
            return *ios_;
        }

        boost::asio::io_service &get_rpc_service( )
        {
            return *rpc_ios_;
        }

        vtrc::shared_ptr<common::connection_list> get_clients( )
        {
            return clients_;
        }

    };

    application::application(  )
        :impl_(new impl)
    { }

    application::application(common::pool_pair &pools)
     :impl_(new impl(&pools.get_io_service( ), &pools.get_rpc_service( )))
    {

    }

    application::application( boost::asio::io_service &ios )
        :impl_(new impl(&ios))
    {}

    application::application( boost::asio::io_service &ios,
                           boost::asio::io_service &rpc_ios)
     :impl_(new impl(&ios, &rpc_ios))
    {}

    application::~application( )
    {
        delete impl_;
    }

    void application::stop_all_clients( )
    {
        impl_->stop_all_clients( );
    }

    common::enviroment &application::get_enviroment( )
    {
        return impl_->get_enviroment( );
    }

    boost::asio::io_service &application::get_io_service( )
    {
        return impl_->get_io_service( );
    }

    boost::asio::io_service &application::get_rpc_service( )
    {
        return impl_->get_rpc_service( );
    }

    vtrc::shared_ptr<common::connection_list> application::get_clients()
    {
        return impl_->get_clients( );
    }

    void application::configure_session(common::connection_iface *  /*c*/,
                                        vtrc_rpc::session_options & /*opts*/)
    {
        /// use default settings
    }

    common::rpc_service_wrapper_sptr application::get_service_by_name(
                                    common::connection_iface * /*connection*/,
                                    const std::string &        /*service_name*/)
    {
        return common::rpc_service_wrapper_sptr( );
    }

    std::string application::get_session_key(common::connection_iface *conn,
                                             const std::string &id)
    {
        return std::string( );
    }

}}
<commit_msg>proto<commit_after>
#include "boost/asio.hpp"

#include "vtrc-application.h"
#include "vtrc-connection-list.h"

#include "vtrc-common/vtrc-enviroment.h"
#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-pool-pair.h"

namespace vtrc { namespace server {

    struct application::impl {

        common::enviroment                  env_;
        boost::asio::io_service            *ios_;
        const bool                          own_ios_;

        boost::asio::io_service            *rpc_ios_;
        const bool                          own_rpc_ios_;

        vtrc::shared_ptr<common::connection_list>   clients_;

        impl( )
            :ios_(new boost::asio::io_service)
            ,own_ios_(true)
            ,rpc_ios_(ios_)
            ,own_rpc_ios_(false)
            ,clients_(common::connection_list::create( ))
        { }

        impl( boost::asio::io_service *ios )
            :ios_(ios)
            ,own_ios_(false)
            ,rpc_ios_(ios)
            ,own_rpc_ios_(false)
            ,clients_(common::connection_list::create( ))
        { }

        impl( boost::asio::io_service *ios, boost::asio::io_service *rpc_ios )
            :ios_(ios)
            ,own_ios_(false)
            ,rpc_ios_(rpc_ios)
            ,own_rpc_ios_(false)
            ,clients_(common::connection_list::create( ))
        { }

        static bool close_all_connection( common::connection_iface_sptr next )
        {
            next->close( );
            return true;
        }

        void stop_all_clients( )
        {
            clients_->foreach_while( close_all_connection );
        }

        ~impl( ) try
        {
            stop_all_clients( );
            clients_->clear( );

            if( own_ios_ )      delete ios_;
            if( own_rpc_ios_ )  delete rpc_ios_;

        } catch ( ... ) {

        }

        common::enviroment &get_enviroment( )
        {
            return env_;
        }

        boost::asio::io_service &get_io_service( )
        {
            return *ios_;
        }

        boost::asio::io_service &get_rpc_service( )
        {
            return *rpc_ios_;
        }

        vtrc::shared_ptr<common::connection_list> get_clients( )
        {
            return clients_;
        }

    };

    application::application(  )
        :impl_(new impl)
    { }

    application::application(common::pool_pair &pools)
     :impl_(new impl(&pools.get_io_service( ), &pools.get_rpc_service( )))
    {

    }

    application::application( boost::asio::io_service &ios )
        :impl_(new impl(&ios))
    {}

    application::application( boost::asio::io_service &ios,
                           boost::asio::io_service &rpc_ios)
     :impl_(new impl(&ios, &rpc_ios))
    {}

    application::~application( )
    {
        delete impl_;
    }

    void application::stop_all_clients( )
    {
        impl_->stop_all_clients( );
    }

    common::enviroment &application::get_enviroment( )
    {
        return impl_->get_enviroment( );
    }

    boost::asio::io_service &application::get_io_service( )
    {
        return impl_->get_io_service( );
    }

    boost::asio::io_service &application::get_rpc_service( )
    {
        return impl_->get_rpc_service( );
    }

    vtrc::shared_ptr<common::connection_list> application::get_clients()
    {
        return impl_->get_clients( );
    }

    void application::configure_session(common::connection_iface *  /*c*/,
                                        vtrc_rpc::session_options & /*opts*/)
    {
        /// use default settings
    }

    common::rpc_service_wrapper_sptr application::get_service_by_name(
                                    common::connection_iface * /*connection*/,
                                    const std::string &        /*service_name*/)
    {
        return common::rpc_service_wrapper_sptr( );
    }

    std::string application::get_session_key(common::connection_iface *conn,
                                             const std::string &id)
    {
        return std::string( );
    }

}}
<|endoftext|>


<commit_before>/*********************************************************************\
	File name        : LanguageList.cpp
	Description      : Implementierung der Klasse CLanguageList
	Created at       : 26.09.01, @ 16:45:39
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/

#include "stdafx.h"
#include "globals.h"

#if (defined _DEBUG) && (defined USE_CPP_NEW_DELETE)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////

CLanguageList::CLanguageList()
{
	m_lLanguages = 0;
	m_ppLanguages = nullptr;
}

CLanguageList::~CLanguageList()
{
	for (Int32 l = 0; l < m_lLanguages; l++)
	{
		DeleteObj(m_ppLanguages[l]);
	}
	bDelete(m_ppLanguages);
}

/*********************************************************************\
	Function name    : CLanguageList::Init
	Description      :
	Created at       : 26.09.01, @ 16:11:23
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
void CLanguageList::Init()
{
	Filename resourcepath = GeGetStartupPath() + Filename("resource");

	#if API_VERSION >= 16000
		// R16 has a new resource directory structure. The c4d_language.str
		// files we are searching for are in resource/modules/c4dplugin/strings_xx.
		// Fix for https://github.com/nr-plugins/resedit/issues/4
		resourcepath = resourcepath + "modules" + "c4dplugin";
	#endif

	AutoAlloc <BrowseFiles> pBrowse;
	pBrowse->Init(resourcepath, false);

	while (pBrowse->GetNext())
	{
		if (pBrowse->IsDir())
		{
			Filename fn = pBrowse->GetFilename();
			if (fn.GetString().SubStr(0, 8).ToLower() == "strings_")
			{
				String idx = fn.GetString();
				idx.Delete(0, 8);

				Filename stringname = resourcepath + fn+Filename("c4d_language.str");
				AutoAlloc <BaseFile> pFile;
				if (!pFile)
					return;
				if (!GeFExist(stringname))
				{
					GeOutString("Missing c4d_language.str to identify the string directory!!!", GEMB_ICONEXCLAMATION);
				}
				else if (pFile->Open(stringname))
				{
					Int32 len = pFile->GetLength();
					Char *buffer = NewMemClear(Char,len + 2);
					if (buffer)
					{
						pFile->ReadBytes(buffer,len);
						buffer[len]=0;

						Int32 i;

						for (i = 0; i < len && buffer[i] >= ' '; i++) { }
						buffer[i] = 0;

						for (i--; i > 0 && buffer[i]== ' '; i--) { }
						buffer[i + 1] = 0;

						AddLanguage(buffer, idx);
						DeleteMem(buffer);
					}
				}
			}
		}
	}

	CriticalAssert(GetNumLanguages() > 0);
}

/*********************************************************************\
	Function name    : CLanguageList::AddLanguage
	Description      :
	Created at       : 26.09.01, @ 16:27:08
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
void CLanguageList::AddLanguage(String strName, String strSuffix)
{
	//TRACE("Found Language\n");
	//TRACE("    Name: "); TRACE_STRING(strName);
	//TRACE("  Suffix: "); TRACE_STRING(strSuffix);

	tagLanguage* pNewLang = NewObjClear(tagLanguage);
	tagLanguage** ppNewLang = bNewDeprecatedUseArraysInstead<tagLanguage*>(m_lLanguages + 1);
	CopyMemType(m_ppLanguages, ppNewLang, m_lLanguages);
	ppNewLang[m_lLanguages] = pNewLang;
	bDelete(m_ppLanguages);
	m_ppLanguages = ppNewLang;
	m_lLanguages++;
	pNewLang->strLanguageName = strName;
	pNewLang->strLanguageSuffix = strSuffix;
}

/*********************************************************************\
	Function name    : CLanguageList::GetName
	Description      :
	Created at       : 26.09.01, @ 16:36:29
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
String CLanguageList::GetName(Int32 a)
{
	if (a < 0 || a >= m_lLanguages) return String("");
	return m_ppLanguages[a]->strLanguageName;
}

/*********************************************************************\
	Function name    : CLanguageList::GetLanguageID
	Description      :
	Created at       : 26.09.01, @ 17:17:34
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
String CLanguageList::GetLanguageSuffix(Int32 a)
{
	if (a < 0 || a >= m_lLanguages) return String("");
	return m_ppLanguages[a]->strLanguageSuffix;
}

/*********************************************************************\
	Function name    : CLanguageList::GetLanguageID
	Description      :
	Created at       : 26.09.01, @ 19:51:04
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
Int32 CLanguageList::GetLanguageID(String strSuffix)
{
	for (Int32 a = 0; a < m_lLanguages; a++)
	{
		if (m_ppLanguages[a]->strLanguageSuffix == strSuffix)
			return a;
	}
	return -1;
}

/*********************************************************************\
	Function name    : CLanguageList::GetName
	Description      :
	Created at       : 26.09.01, @ 21:41:10
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
String CLanguageList::GetName(String strSuffix)
{
	Int32 l = GetLanguageID(strSuffix);
	if (l < 0) return String("");

	return GetName(l);
}

String CLanguageList::GetLanguageName(Int32 a)
{
	if (a < 0 || a >= m_lLanguages) return String("");
	return m_ppLanguages[a]->strLanguageName + "(" + m_ppLanguages[a]->strLanguageSuffix + ")";
}
<commit_msg>Fix CLanguageList::Init() using runtime-check<commit_after>/*********************************************************************\
	File name        : LanguageList.cpp
	Description      : Implementierung der Klasse CLanguageList
	Created at       : 26.09.01, @ 16:45:39
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/

#include "stdafx.h"
#include "globals.h"

#if (defined _DEBUG) && (defined USE_CPP_NEW_DELETE)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////

CLanguageList::CLanguageList()
{
	m_lLanguages = 0;
	m_ppLanguages = nullptr;
}

CLanguageList::~CLanguageList()
{
	for (Int32 l = 0; l < m_lLanguages; l++)
	{
		DeleteObj(m_ppLanguages[l]);
	}
	bDelete(m_ppLanguages);
}

/*********************************************************************\
	Function name    : CLanguageList::Init
	Description      :
	Created at       : 26.09.01, @ 16:11:23
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
void CLanguageList::Init()
{
	Filename resourcepath = GeGetStartupPath() + Filename("resource");

	if (GetC4DVersion() >= 16000) {
		// R16 has a new resource directory structure. The c4d_language.str
		// files we are searching for are in resource/modules/c4dplugin/strings_xx.
		// Fix for https://github.com/nr-plugins/resedit/issues/4
		resourcepath = resourcepath + "modules" + "c4dplugin";
	}

	AutoAlloc <BrowseFiles> pBrowse;
	pBrowse->Init(resourcepath, false);

	while (pBrowse->GetNext())
	{
		if (pBrowse->IsDir())
		{
			Filename fn = pBrowse->GetFilename();
			if (fn.GetString().SubStr(0, 8).ToLower() == "strings_")
			{
				String idx = fn.GetString();
				idx.Delete(0, 8);

				Filename stringname = resourcepath + fn+Filename("c4d_language.str");
				AutoAlloc <BaseFile> pFile;
				if (!pFile)
					return;
				if (!GeFExist(stringname))
				{
					GeOutString("Missing c4d_language.str to identify the string directory!!!", GEMB_ICONEXCLAMATION);
				}
				else if (pFile->Open(stringname))
				{
					Int32 len = pFile->GetLength();
					Char *buffer = NewMemClear(Char,len + 2);
					if (buffer)
					{
						pFile->ReadBytes(buffer,len);
						buffer[len]=0;

						Int32 i;

						for (i = 0; i < len && buffer[i] >= ' '; i++) { }
						buffer[i] = 0;

						for (i--; i > 0 && buffer[i]== ' '; i--) { }
						buffer[i + 1] = 0;

						AddLanguage(buffer, idx);
						DeleteMem(buffer);
					}
				}
			}
		}
	}

	CriticalAssert(GetNumLanguages() > 0);
}

/*********************************************************************\
	Function name    : CLanguageList::AddLanguage
	Description      :
	Created at       : 26.09.01, @ 16:27:08
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
void CLanguageList::AddLanguage(String strName, String strSuffix)
{
	//TRACE("Found Language\n");
	//TRACE("    Name: "); TRACE_STRING(strName);
	//TRACE("  Suffix: "); TRACE_STRING(strSuffix);

	tagLanguage* pNewLang = NewObjClear(tagLanguage);
	tagLanguage** ppNewLang = bNewDeprecatedUseArraysInstead<tagLanguage*>(m_lLanguages + 1);
	CopyMemType(m_ppLanguages, ppNewLang, m_lLanguages);
	ppNewLang[m_lLanguages] = pNewLang;
	bDelete(m_ppLanguages);
	m_ppLanguages = ppNewLang;
	m_lLanguages++;
	pNewLang->strLanguageName = strName;
	pNewLang->strLanguageSuffix = strSuffix;
}

/*********************************************************************\
	Function name    : CLanguageList::GetName
	Description      :
	Created at       : 26.09.01, @ 16:36:29
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
String CLanguageList::GetName(Int32 a)
{
	if (a < 0 || a >= m_lLanguages) return String("");
	return m_ppLanguages[a]->strLanguageName;
}

/*********************************************************************\
	Function name    : CLanguageList::GetLanguageID
	Description      :
	Created at       : 26.09.01, @ 17:17:34
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
String CLanguageList::GetLanguageSuffix(Int32 a)
{
	if (a < 0 || a >= m_lLanguages) return String("");
	return m_ppLanguages[a]->strLanguageSuffix;
}

/*********************************************************************\
	Function name    : CLanguageList::GetLanguageID
	Description      :
	Created at       : 26.09.01, @ 19:51:04
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
Int32 CLanguageList::GetLanguageID(String strSuffix)
{
	for (Int32 a = 0; a < m_lLanguages; a++)
	{
		if (m_ppLanguages[a]->strLanguageSuffix == strSuffix)
			return a;
	}
	return -1;
}

/*********************************************************************\
	Function name    : CLanguageList::GetName
	Description      :
	Created at       : 26.09.01, @ 21:41:10
	Created by       : Thomas Kunert
	Modified by      :
\*********************************************************************/
String CLanguageList::GetName(String strSuffix)
{
	Int32 l = GetLanguageID(strSuffix);
	if (l < 0) return String("");

	return GetName(l);
}

String CLanguageList::GetLanguageName(Int32 a)
{
	if (a < 0 || a >= m_lLanguages) return String("");
	return m_ppLanguages[a]->strLanguageName + "(" + m_ppLanguages[a]->strLanguageSuffix + ")";
}
<|endoftext|>


<commit_before><commit_msg>Pretend to itereate over a map that has only one element (by definition).<commit_after><|endoftext|>


<commit_before><commit_msg>Fix custom UI port notifications<commit_after><|endoftext|>


<commit_before><commit_msg>Use WSAPoll only on win version >= 0x0600 (#79)<commit_after><|endoftext|>


<commit_before><commit_msg>baseValueForKeyPathInHolder now returns object, instead of nullptr value<commit_after><|endoftext|>


<commit_before><commit_msg>Select first item<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "ephemeral_bucket.h"

#include "ep_engine.h"
#include "ep_types.h"
#include "ephemeral_tombstone_purger.h"
#include "ephemeral_vb.h"
#include "ephemeral_vb_count_visitor.h"
#include "failover-table.h"

#include <platform/sized_buffer.h>

/**
 * A configuration value changed listener that responds to Ephemeral bucket
 * parameter changes.
 */
class EphemeralValueChangedListener : public ValueChangedListener {
public:
    EphemeralValueChangedListener(EphemeralBucket& bucket)
        : bucket(bucket) {
    }

    void stringValueChanged(const std::string& key,
                            const char* value) override {
        if (key == "ephemeral_full_policy") {
            if (cb::const_char_buffer(value) == "auto_delete") {
                bucket.enableItemPager();
            } else if (cb::const_char_buffer(value) == "fail_new_data") {
                bucket.disableItemPager();
            } else {
                LOG(EXTENSION_LOG_WARNING,
                    "EphemeralValueChangedListener: Invalid value '%s' for "
                    "'ephemeral_full_policy - ignoring.",
                    value);
            }
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "EphemeralValueChangedListener: Failed to change value for "
                "unknown key '%s'",
                key.c_str());
        }
    }

    void ssizeValueChanged(const std::string& key, ssize_t value) override {
        if (key == "ephemeral_metadata_purge_age") {
            if (value == -1) {
                bucket.disableTombstonePurgerTask();
            }
            // Any non-negative value will be picked up by the Task the
            // next time it runs.
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "EphemeralValueChangedListener: Failed to change value for "
                "unknown key '%s'",
                key.c_str());
        }
    }

    void sizeValueChanged(const std::string& key, size_t value) override {
        if (key == "ephemeral_metadata_purge_interval") {
            // Cancel and re-schedule the task to pick up the new interval.
            bucket.enableTombstonePurgerTask();
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "EphemeralValueChangedListener: Failed to change value for "
                "unknown key '%s'",
                key.c_str());
        }
    }

private:
    EphemeralBucket& bucket;
};

EphemeralBucket::EphemeralBucket(EventuallyPersistentEngine& theEngine)
    : KVBucket(theEngine),
      notifyHpReqTask(make_STRCPtr<NotifyHighPriorityReqTask>(theEngine)) {
    /* We always have VALUE_ONLY eviction policy because a key not
       present in HashTable implies key not present at all.
       Note: This should not be confused with the eviction algorithm
             that we are going to use like NRU, FIFO etc. */
    eviction_policy = VALUE_ONLY;
}

EphemeralBucket::~EphemeralBucket() {
    ExecutorPool::get()->cancel(notifyHpReqTask->getId());
}

bool EphemeralBucket::initialize() {
    KVBucket::initialize();
    auto& config = engine.getConfiguration();

    // Item pager - only scheduled if "auto_delete" is specified as the bucket
    // full policy, but always add a value changed listener so we can handle
    // dynamic config changes (and later schedule it).
    if (config.getEphemeralFullPolicy() == "auto_delete") {
        enableItemPager();
    }
    engine.getConfiguration().addValueChangedListener(
            "ephemeral_full_policy", new EphemeralValueChangedListener(*this));

    // Tombstone purger - scheduled periodically as long as we have a
    // non-zero interval. Can be dynamically adjusted, so add config listeners.
    tombstonePurgerTask = new EphTombstonePurgerTask(&engine, stats);
    auto interval = config.getEphemeralMetadataPurgeInterval();
    if (interval > 0) {
        enableTombstonePurgerTask();
    }
    config.addValueChangedListener("ephemeral_metadata_purge_age",
                                   new EphemeralValueChangedListener(*this));
    config.addValueChangedListener("ephemeral_metadata_purge_interval",
                                   new EphemeralValueChangedListener(*this));

    // High priority vbucket request notification task
    ExecutorPool::get()->schedule(notifyHpReqTask);

    return true;
}

VBucketPtr EphemeralBucket::makeVBucket(
        VBucket::id_type id,
        vbucket_state_t state,
        KVShard* shard,
        std::unique_ptr<FailoverTable> table,
        NewSeqnoCallback newSeqnoCb,
        vbucket_state_t initState,
        int64_t lastSeqno,
        uint64_t lastSnapStart,
        uint64_t lastSnapEnd,
        uint64_t purgeSeqno,
        uint64_t maxCas,
        const std::string& collectionsManifest) {
    // Not using make_shared or allocate_shared
    // 1. make_shared doesn't accept a Deleter
    // 2. allocate_shared has inconsistencies between platforms in calling
    //    alloc.destroy (libc++ doesn't call it)
    return VBucketPtr(new EphemeralVBucket(id,
                                           state,
                                           stats,
                                           engine.getCheckpointConfig(),
                                           shard,
                                           lastSeqno,
                                           lastSnapStart,
                                           lastSnapEnd,
                                           std::move(table),
                                           std::move(newSeqnoCb),
                                           engine.getConfiguration(),
                                           eviction_policy,
                                           initState,
                                           purgeSeqno,
                                           maxCas,
                                           collectionsManifest),
                      VBucket::DeferredDeleter(engine));
}

void EphemeralBucket::completeStatsVKey(const void* cookie,
                                        const DocKey& key,
                                        uint16_t vbid,
                                        uint64_t bySeqNum) {
    throw std::logic_error(
            "EphemeralBucket::completeStatsVKey() "
            "is not a valid call. Called on vb " +
            std::to_string(vbid) + "for key: " +
            std::string(reinterpret_cast<const char*>(key.data()), key.size()));
}

RollbackResult EphemeralBucket::doRollback(uint16_t vbid,
                                           uint64_t rollbackSeqno) {
    /* For now we always rollback to zero */
    return RollbackResult(/* not a success as we would rather reset vb */ false,
                          /* highSeqno */ 0,
                          /* snapStartSeqno */ 0,
                          /* snapEndSeqno */ 0);
}

void EphemeralBucket::enableTombstonePurgerTask() {
    ExecutorPool::get()->cancel(tombstonePurgerTask->getId());
    ExecutorPool::get()->schedule(tombstonePurgerTask);
}

void EphemeralBucket::disableTombstonePurgerTask() {
    ExecutorPool::get()->cancel(tombstonePurgerTask->getId());
}

void EphemeralBucket::reconfigureForEphemeral(Configuration& config) {
    // Disable access scanner - we never create it anyway, but set to
    // disabled as to not mislead the user via stats.
    config.setAccessScannerEnabled(false);
    // Disable Bloom filter - it is currently no use for us (both
    // alive+deleted keys are kept in HashTable).
    config.setBfilterEnabled(false);
    // Disable warmup - it is not applicable to Ephemeral buckets.
    config.setWarmup(false);
    // Disable TAP - not supported for Ephemeral.
    config.setTap(false);
}

size_t EphemeralBucket::getNumPersistedDeletes(uint16_t vbid) {
    /* the name is getNumPersistedDeletes, in ephemeral buckets the equivalent
       meaning is the number of deletes seen by the vbucket.
       This is needed by ns-server during vb-takeover */
    VBucketPtr vb = getVBucket(vbid);
    return vb->getNumInMemoryDeletes();
}

void EphemeralBucket::notifyNewSeqno(const uint16_t vbid,
                                     const VBNotifyCtx& notifyCtx) {
    if (notifyCtx.notifyFlusher) {
        notifyFlusher(vbid);
    }
    if (notifyCtx.notifyReplication) {
        notifyReplication(vbid, notifyCtx.bySeqno);
    }

    /* In ephemeral buckets we must notify high priority requests as well.
       We do not wait for persistence to notify high priority requests */
    VBucketPtr vb = getVBucket(vbid);

    auto toNotify = vb->getHighPriorityNotifications(
            engine, notifyCtx.bySeqno, HighPriorityVBNotify::Seqno);

    if (toNotify.size() && notifyHpReqTask) {
        notifyHpReqTask->wakeup(std::move(toNotify));
    }
}

// Protected methods //////////////////////////////////////////////////////////

std::unique_ptr<VBucketCountVisitor> EphemeralBucket::makeVBCountVisitor(
        vbucket_state_t state) {
    return std::make_unique<EphemeralVBucket::CountVisitor>(state);
}

void EphemeralBucket::appendAggregatedVBucketStats(VBucketCountVisitor& active,
                                                   VBucketCountVisitor& replica,
                                                   VBucketCountVisitor& pending,
                                                   VBucketCountVisitor& dead,
                                                   const void* cookie,
                                                   ADD_STAT add_stat) {

    // The CountVisitors passed in are expected to all be Ephemeral subclasses.
    auto& ephActive = dynamic_cast<EphemeralVBucket::CountVisitor&>(active);
    auto& ephReplica = dynamic_cast<EphemeralVBucket::CountVisitor&>(replica);
    auto& ephPending = dynamic_cast<EphemeralVBucket::CountVisitor&>(pending);

    // Add stats for the base class:
    KVBucket::appendAggregatedVBucketStats(
            active, replica, pending, dead, cookie, add_stat);

    // Add Ephemeral-specific stats.

#define DO_STAT(k, v)                            \
    do {                                         \
        add_casted_stat(k, v, add_stat, cookie); \
    } while (0)

    // Active vBuckets:
    DO_STAT("vb_active_auto_delete_count", ephActive.autoDeleteCount);
    DO_STAT("vb_active_seqlist_count", ephActive.seqlistCount);
    DO_STAT("vb_active_seqlist_deleted_count", ephActive.seqlistDeletedCount);
    DO_STAT("vb_active_seqlist_read_range_count",
            ephActive.seqlistReadRangeCount);
    DO_STAT("vb_active_seqlist_stale_count", ephActive.seqlistStaleCount);
    DO_STAT("vb_active_seqlist_stale_value_bytes",
            ephActive.seqlistStaleValueBytes);
    DO_STAT("vb_active_seqlist_stale_metadata_bytes",
            ephActive.seqlistStaleMetadataBytes);

    // Replica vBuckets:
    DO_STAT("vb_replica_auto_delete_count", ephReplica.autoDeleteCount);
    DO_STAT("vb_replica_seqlist_count", ephReplica.seqlistCount);
    DO_STAT("vb_replica_seqlist_deleted_count", ephReplica.seqlistDeletedCount);
    DO_STAT("vb_replica_seqlist_read_range_count",
            ephReplica.seqlistReadRangeCount);
    DO_STAT("vb_replica_seqlist_stale_count", ephReplica.seqlistStaleCount);
    DO_STAT("vb_replica_seqlist_stale_value_bytes",
            ephReplica.seqlistStaleValueBytes);
    DO_STAT("vb_replica_seqlist_stale_metadata_bytes",
            ephReplica.seqlistStaleMetadataBytes);

    // Pending vBuckets:
    DO_STAT("vb_pending_auto_delete_count", ephPending.autoDeleteCount);
    DO_STAT("vb_pending_seqlist_count", ephPending.seqlistCount);
    DO_STAT("vb_pending_seqlist_deleted_count", ephPending.seqlistDeletedCount);
    DO_STAT("vb_pending_seqlist_read_range_count",
            ephPending.seqlistReadRangeCount);
    DO_STAT("vb_pending_seqlist_stale_count", ephPending.seqlistStaleCount);
    DO_STAT("vb_pending_seqlist_stale_value_bytes",
            ephPending.seqlistStaleValueBytes);
    DO_STAT("vb_pending_seqlist_stale_metadata_bytes",
            ephPending.seqlistStaleMetadataBytes);
#undef DO_STAT
}

EphemeralBucket::NotifyHighPriorityReqTask::NotifyHighPriorityReqTask(
        EventuallyPersistentEngine& e)
    : GlobalTask(&e,
                 TaskId::NotifyHighPriorityReqTask,
                 std::numeric_limits<int>::max(),
                 false) {
}

bool EphemeralBucket::NotifyHighPriorityReqTask::run() {
    std::map<const void*, ENGINE_ERROR_CODE> notifyQ;
    {
        /* It is necessary that the toNotifyLock is not held while
           actually notifying. */
        std::lock_guard<std::mutex> lg(toNotifyLock);
        notifyQ = std::move(toNotify);
    }

    for (auto& notify : notifyQ) {
        LOG(EXTENSION_LOG_NOTICE,
            "%s for cookie :%p and status %d",
            to_string(getDescription()).c_str(),
            notify.first,
            notify.second);
        engine->notifyIOComplete(notify.first, notify.second);
    }

    /* Lets assume that the task will be explicitly woken */
    snooze(std::numeric_limits<int>::max());

    /* But, also check if another thread already tried to wake up the task */
    bool scheduleSoon = false;
    {
        std::lock_guard<std::mutex> lg(toNotifyLock);
        if (toNotify.size()) {
            scheduleSoon = true;
        }
    }

    if (scheduleSoon) {
        /* Good to call snooze without holding toNotifyLock */
        snooze(0);
    }

    /* Run the task again after snoozing */
    return true;
}

cb::const_char_buffer
EphemeralBucket::NotifyHighPriorityReqTask::getDescription() {
    return "Ephemeral: Notify HighPriority Request";
}

void EphemeralBucket::NotifyHighPriorityReqTask::wakeup(
        std::map<const void*, ENGINE_ERROR_CODE> notifies) {
    {
        /* Add the connections to be notified */
        std::lock_guard<std::mutex> lg(toNotifyLock);
        toNotify.insert(make_move_iterator(begin(notifies)),
                        make_move_iterator(end(notifies)));
    }

    /* wake up the task */
    ExecutorPool::get()->wake(getId());
}
<commit_msg>MB-24472 [Ephemeral]: Check for null vBucket in getNumPersistedDeletes<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "ephemeral_bucket.h"

#include "ep_engine.h"
#include "ep_types.h"
#include "ephemeral_tombstone_purger.h"
#include "ephemeral_vb.h"
#include "ephemeral_vb_count_visitor.h"
#include "failover-table.h"

#include <platform/sized_buffer.h>

/**
 * A configuration value changed listener that responds to Ephemeral bucket
 * parameter changes.
 */
class EphemeralValueChangedListener : public ValueChangedListener {
public:
    EphemeralValueChangedListener(EphemeralBucket& bucket)
        : bucket(bucket) {
    }

    void stringValueChanged(const std::string& key,
                            const char* value) override {
        if (key == "ephemeral_full_policy") {
            if (cb::const_char_buffer(value) == "auto_delete") {
                bucket.enableItemPager();
            } else if (cb::const_char_buffer(value) == "fail_new_data") {
                bucket.disableItemPager();
            } else {
                LOG(EXTENSION_LOG_WARNING,
                    "EphemeralValueChangedListener: Invalid value '%s' for "
                    "'ephemeral_full_policy - ignoring.",
                    value);
            }
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "EphemeralValueChangedListener: Failed to change value for "
                "unknown key '%s'",
                key.c_str());
        }
    }

    void ssizeValueChanged(const std::string& key, ssize_t value) override {
        if (key == "ephemeral_metadata_purge_age") {
            if (value == -1) {
                bucket.disableTombstonePurgerTask();
            }
            // Any non-negative value will be picked up by the Task the
            // next time it runs.
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "EphemeralValueChangedListener: Failed to change value for "
                "unknown key '%s'",
                key.c_str());
        }
    }

    void sizeValueChanged(const std::string& key, size_t value) override {
        if (key == "ephemeral_metadata_purge_interval") {
            // Cancel and re-schedule the task to pick up the new interval.
            bucket.enableTombstonePurgerTask();
        } else {
            LOG(EXTENSION_LOG_WARNING,
                "EphemeralValueChangedListener: Failed to change value for "
                "unknown key '%s'",
                key.c_str());
        }
    }

private:
    EphemeralBucket& bucket;
};

EphemeralBucket::EphemeralBucket(EventuallyPersistentEngine& theEngine)
    : KVBucket(theEngine),
      notifyHpReqTask(make_STRCPtr<NotifyHighPriorityReqTask>(theEngine)) {
    /* We always have VALUE_ONLY eviction policy because a key not
       present in HashTable implies key not present at all.
       Note: This should not be confused with the eviction algorithm
             that we are going to use like NRU, FIFO etc. */
    eviction_policy = VALUE_ONLY;
}

EphemeralBucket::~EphemeralBucket() {
    ExecutorPool::get()->cancel(notifyHpReqTask->getId());
}

bool EphemeralBucket::initialize() {
    KVBucket::initialize();
    auto& config = engine.getConfiguration();

    // Item pager - only scheduled if "auto_delete" is specified as the bucket
    // full policy, but always add a value changed listener so we can handle
    // dynamic config changes (and later schedule it).
    if (config.getEphemeralFullPolicy() == "auto_delete") {
        enableItemPager();
    }
    engine.getConfiguration().addValueChangedListener(
            "ephemeral_full_policy", new EphemeralValueChangedListener(*this));

    // Tombstone purger - scheduled periodically as long as we have a
    // non-zero interval. Can be dynamically adjusted, so add config listeners.
    tombstonePurgerTask = new EphTombstonePurgerTask(&engine, stats);
    auto interval = config.getEphemeralMetadataPurgeInterval();
    if (interval > 0) {
        enableTombstonePurgerTask();
    }
    config.addValueChangedListener("ephemeral_metadata_purge_age",
                                   new EphemeralValueChangedListener(*this));
    config.addValueChangedListener("ephemeral_metadata_purge_interval",
                                   new EphemeralValueChangedListener(*this));

    // High priority vbucket request notification task
    ExecutorPool::get()->schedule(notifyHpReqTask);

    return true;
}

VBucketPtr EphemeralBucket::makeVBucket(
        VBucket::id_type id,
        vbucket_state_t state,
        KVShard* shard,
        std::unique_ptr<FailoverTable> table,
        NewSeqnoCallback newSeqnoCb,
        vbucket_state_t initState,
        int64_t lastSeqno,
        uint64_t lastSnapStart,
        uint64_t lastSnapEnd,
        uint64_t purgeSeqno,
        uint64_t maxCas,
        const std::string& collectionsManifest) {
    // Not using make_shared or allocate_shared
    // 1. make_shared doesn't accept a Deleter
    // 2. allocate_shared has inconsistencies between platforms in calling
    //    alloc.destroy (libc++ doesn't call it)
    return VBucketPtr(new EphemeralVBucket(id,
                                           state,
                                           stats,
                                           engine.getCheckpointConfig(),
                                           shard,
                                           lastSeqno,
                                           lastSnapStart,
                                           lastSnapEnd,
                                           std::move(table),
                                           std::move(newSeqnoCb),
                                           engine.getConfiguration(),
                                           eviction_policy,
                                           initState,
                                           purgeSeqno,
                                           maxCas,
                                           collectionsManifest),
                      VBucket::DeferredDeleter(engine));
}

void EphemeralBucket::completeStatsVKey(const void* cookie,
                                        const DocKey& key,
                                        uint16_t vbid,
                                        uint64_t bySeqNum) {
    throw std::logic_error(
            "EphemeralBucket::completeStatsVKey() "
            "is not a valid call. Called on vb " +
            std::to_string(vbid) + "for key: " +
            std::string(reinterpret_cast<const char*>(key.data()), key.size()));
}

RollbackResult EphemeralBucket::doRollback(uint16_t vbid,
                                           uint64_t rollbackSeqno) {
    /* For now we always rollback to zero */
    return RollbackResult(/* not a success as we would rather reset vb */ false,
                          /* highSeqno */ 0,
                          /* snapStartSeqno */ 0,
                          /* snapEndSeqno */ 0);
}

void EphemeralBucket::enableTombstonePurgerTask() {
    ExecutorPool::get()->cancel(tombstonePurgerTask->getId());
    ExecutorPool::get()->schedule(tombstonePurgerTask);
}

void EphemeralBucket::disableTombstonePurgerTask() {
    ExecutorPool::get()->cancel(tombstonePurgerTask->getId());
}

void EphemeralBucket::reconfigureForEphemeral(Configuration& config) {
    // Disable access scanner - we never create it anyway, but set to
    // disabled as to not mislead the user via stats.
    config.setAccessScannerEnabled(false);
    // Disable Bloom filter - it is currently no use for us (both
    // alive+deleted keys are kept in HashTable).
    config.setBfilterEnabled(false);
    // Disable warmup - it is not applicable to Ephemeral buckets.
    config.setWarmup(false);
    // Disable TAP - not supported for Ephemeral.
    config.setTap(false);
}

size_t EphemeralBucket::getNumPersistedDeletes(uint16_t vbid) {
    /* the name is getNumPersistedDeletes, in ephemeral buckets the equivalent
       meaning is the number of deletes seen by the vbucket.
       This is needed by ns-server during vb-takeover */
    VBucketPtr vb = getVBucket(vbid);
    if (vb) {
        return vb->getNumInMemoryDeletes();
    }
    throw std::runtime_error(
            "EphemeralBucket::getNumPersistedDeletes: No vbucket with id '" +
            std::to_string(vbid) + "' in vbMap");
}

void EphemeralBucket::notifyNewSeqno(const uint16_t vbid,
                                     const VBNotifyCtx& notifyCtx) {
    if (notifyCtx.notifyFlusher) {
        notifyFlusher(vbid);
    }
    if (notifyCtx.notifyReplication) {
        notifyReplication(vbid, notifyCtx.bySeqno);
    }

    /* In ephemeral buckets we must notify high priority requests as well.
       We do not wait for persistence to notify high priority requests */
    VBucketPtr vb = getVBucket(vbid);

    auto toNotify = vb->getHighPriorityNotifications(
            engine, notifyCtx.bySeqno, HighPriorityVBNotify::Seqno);

    if (toNotify.size() && notifyHpReqTask) {
        notifyHpReqTask->wakeup(std::move(toNotify));
    }
}

// Protected methods //////////////////////////////////////////////////////////

std::unique_ptr<VBucketCountVisitor> EphemeralBucket::makeVBCountVisitor(
        vbucket_state_t state) {
    return std::make_unique<EphemeralVBucket::CountVisitor>(state);
}

void EphemeralBucket::appendAggregatedVBucketStats(VBucketCountVisitor& active,
                                                   VBucketCountVisitor& replica,
                                                   VBucketCountVisitor& pending,
                                                   VBucketCountVisitor& dead,
                                                   const void* cookie,
                                                   ADD_STAT add_stat) {

    // The CountVisitors passed in are expected to all be Ephemeral subclasses.
    auto& ephActive = dynamic_cast<EphemeralVBucket::CountVisitor&>(active);
    auto& ephReplica = dynamic_cast<EphemeralVBucket::CountVisitor&>(replica);
    auto& ephPending = dynamic_cast<EphemeralVBucket::CountVisitor&>(pending);

    // Add stats for the base class:
    KVBucket::appendAggregatedVBucketStats(
            active, replica, pending, dead, cookie, add_stat);

    // Add Ephemeral-specific stats.

#define DO_STAT(k, v)                            \
    do {                                         \
        add_casted_stat(k, v, add_stat, cookie); \
    } while (0)

    // Active vBuckets:
    DO_STAT("vb_active_auto_delete_count", ephActive.autoDeleteCount);
    DO_STAT("vb_active_seqlist_count", ephActive.seqlistCount);
    DO_STAT("vb_active_seqlist_deleted_count", ephActive.seqlistDeletedCount);
    DO_STAT("vb_active_seqlist_read_range_count",
            ephActive.seqlistReadRangeCount);
    DO_STAT("vb_active_seqlist_stale_count", ephActive.seqlistStaleCount);
    DO_STAT("vb_active_seqlist_stale_value_bytes",
            ephActive.seqlistStaleValueBytes);
    DO_STAT("vb_active_seqlist_stale_metadata_bytes",
            ephActive.seqlistStaleMetadataBytes);

    // Replica vBuckets:
    DO_STAT("vb_replica_auto_delete_count", ephReplica.autoDeleteCount);
    DO_STAT("vb_replica_seqlist_count", ephReplica.seqlistCount);
    DO_STAT("vb_replica_seqlist_deleted_count", ephReplica.seqlistDeletedCount);
    DO_STAT("vb_replica_seqlist_read_range_count",
            ephReplica.seqlistReadRangeCount);
    DO_STAT("vb_replica_seqlist_stale_count", ephReplica.seqlistStaleCount);
    DO_STAT("vb_replica_seqlist_stale_value_bytes",
            ephReplica.seqlistStaleValueBytes);
    DO_STAT("vb_replica_seqlist_stale_metadata_bytes",
            ephReplica.seqlistStaleMetadataBytes);

    // Pending vBuckets:
    DO_STAT("vb_pending_auto_delete_count", ephPending.autoDeleteCount);
    DO_STAT("vb_pending_seqlist_count", ephPending.seqlistCount);
    DO_STAT("vb_pending_seqlist_deleted_count", ephPending.seqlistDeletedCount);
    DO_STAT("vb_pending_seqlist_read_range_count",
            ephPending.seqlistReadRangeCount);
    DO_STAT("vb_pending_seqlist_stale_count", ephPending.seqlistStaleCount);
    DO_STAT("vb_pending_seqlist_stale_value_bytes",
            ephPending.seqlistStaleValueBytes);
    DO_STAT("vb_pending_seqlist_stale_metadata_bytes",
            ephPending.seqlistStaleMetadataBytes);
#undef DO_STAT
}

EphemeralBucket::NotifyHighPriorityReqTask::NotifyHighPriorityReqTask(
        EventuallyPersistentEngine& e)
    : GlobalTask(&e,
                 TaskId::NotifyHighPriorityReqTask,
                 std::numeric_limits<int>::max(),
                 false) {
}

bool EphemeralBucket::NotifyHighPriorityReqTask::run() {
    std::map<const void*, ENGINE_ERROR_CODE> notifyQ;
    {
        /* It is necessary that the toNotifyLock is not held while
           actually notifying. */
        std::lock_guard<std::mutex> lg(toNotifyLock);
        notifyQ = std::move(toNotify);
    }

    for (auto& notify : notifyQ) {
        LOG(EXTENSION_LOG_NOTICE,
            "%s for cookie :%p and status %d",
            to_string(getDescription()).c_str(),
            notify.first,
            notify.second);
        engine->notifyIOComplete(notify.first, notify.second);
    }

    /* Lets assume that the task will be explicitly woken */
    snooze(std::numeric_limits<int>::max());

    /* But, also check if another thread already tried to wake up the task */
    bool scheduleSoon = false;
    {
        std::lock_guard<std::mutex> lg(toNotifyLock);
        if (toNotify.size()) {
            scheduleSoon = true;
        }
    }

    if (scheduleSoon) {
        /* Good to call snooze without holding toNotifyLock */
        snooze(0);
    }

    /* Run the task again after snoozing */
    return true;
}

cb::const_char_buffer
EphemeralBucket::NotifyHighPriorityReqTask::getDescription() {
    return "Ephemeral: Notify HighPriority Request";
}

void EphemeralBucket::NotifyHighPriorityReqTask::wakeup(
        std::map<const void*, ENGINE_ERROR_CODE> notifies) {
    {
        /* Add the connections to be notified */
        std::lock_guard<std::mutex> lg(toNotifyLock);
        toNotify.insert(make_move_iterator(begin(notifies)),
                        make_move_iterator(end(notifies)));
    }

    /* wake up the task */
    ExecutorPool::get()->wake(getId());
}
<|endoftext|>


<commit_before>#include "gui/boardwidget.hpp"

#include <cmath>

#include <SFML/Graphics/Vertex.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <SFML/Graphics/PrimitiveType.hpp>
#include <SFML/Graphics/RenderTarget.hpp>

#include <SFML/Graphics/CircleShape.hpp>
#include <SFML/Graphics/Color.hpp>

#include <iostream>
#include <stdio.h>

#include "engine/engine.hpp"
#include "engine/player.hpp"
#include "engine/pathfinding/path.hpp"
#include "gui/guihandler.hpp"
#include "gui/cursor.hpp"
#include "gui/damagenumber.hpp"

namespace qrw
{
	BoardWidget::BoardWidget(GuiHandler* guihandler, Engine* engine, float width, float height)
	: Widget(guihandler->getRenderWindow(), width, height),
	  board(0),
	  engine(engine),
	  spritedimensions(0.0),
	  singlespritescale(0.0),
	  path(0),
	  deploywindow(guihandler->getDeployWindow())
	{
		printf("boardrenderer position: x=%f / y=%f\n", getGlobalBounds().left, getGlobalBounds().top);
		printf("boardrenderer size: w=%f / h=%f\n", getSize().x, getSize().y);

		// Create required sprites.
		TextureManager* texturemanager = TextureManager::getInstance();

		plainsquare = new sf::Sprite(*texturemanager->getTexture("plainsquare"));
		terrainsprites[ET_WOOD] = new sf::Sprite(*texturemanager->getTexture("wood"));
		terrainsprites[ET_HILL] = new sf::Sprite(*texturemanager->getTexture("hill"));
		terrainsprites[ET_WALL] = new sf::Sprite(*texturemanager->getTexture("wall"));
		p1unitsprites[EUT_SWORDMAN] = new sf::Sprite(*texturemanager->getTexture("p1swordman"));
		p1unitsprites[EUT_ARCHER] = new sf::Sprite(*texturemanager->getTexture("p1archer"));
		p1unitsprites[EUT_SPEARMAN] = new sf::Sprite(*texturemanager->getTexture("p1spearman"));
		p2unitsprites[EUT_SWORDMAN] = new sf::Sprite(*texturemanager->getTexture("p2swordman"));
		p2unitsprites[EUT_ARCHER] = new sf::Sprite(*texturemanager->getTexture("p2archer"));
		p2unitsprites[EUT_SPEARMAN] = new sf::Sprite(*texturemanager->getTexture("p2spearman"));

		signalmousemoved.connect(std::bind(&BoardWidget::updateCursor, this));
		signalmouseentered.connect(std::bind(&BoardWidget::updateCursor, this));
		signalclicked.connect(std::bind(&BoardWidget::leftClicked, this));
		signalrightclicked.connect(std::bind(&BoardWidget::rightClicked, this));
		signalkeypressed.connect(std::bind(&BoardWidget::keyPressed, this, std::placeholders::_1));
	}

	BoardWidget::~BoardWidget()
	{
		delete plainsquare;
	}

	void BoardWidget::setBoard(Board* board)
	{
		this->board = board;
		calcSpriteDimensions(board->getWidth(), board->getHeight());
	}

	void BoardWidget::draw(sf::RenderTarget &target, sf::RenderStates states) const
	{
		sf::Vector2f targetsize = target.getView().getSize();
		targetsize.x -= 180.0;
		int width = board->getWidth();
		int height = board->getHeight();

		sf::Vector2f spritescale(singlespritescale, singlespritescale);
		sf::VertexArray vertices(sf::Lines, 0);
		Square *square = 0;
		Unit *unit = 0;
		Terrain *terrain = 0;
		sf::Vector2f currpos;

		sf::Vector2i cursorpos = Cursor::getCursor()->getPosition();
		sf::Vector2i childcursorpos(-1, -1);

		if(Cursor::getCursor()->getChild() != 0)
		{
			childcursorpos.x = Cursor::getCursor()->getChild()->getPosition().x;
			childcursorpos.y = Cursor::getCursor()->getChild()->getPosition().y;
		}

		for(int i = 0; i < width; ++i)
		{
			for(int j = 0; j < height; ++j)
			{
				currpos.x = i * spritedimensions;
				currpos.y = j * spritedimensions;

				plainsquare->setPosition(currpos);
				plainsquare->setScale(spritescale);
				target.draw(*plainsquare);

				square = board->getSquare(i, j);
				terrain = square->getTerrain();
				unit = square->getUnit();
				// Render cursor
				if(cursorpos.x == i && cursorpos.y == j)
					Cursor::getCursor()->draw(target, currpos, spritedimensions);
				if(childcursorpos.x == i && childcursorpos.y == j)
					Cursor::getCursor()->drawChild(target, currpos, spritedimensions);

				// Render Terrain
				if(terrain != 0)
				{
					drawTerrain(target, terrain->getType(), currpos, spritescale);
				}
				// Render Units
				if(unit != 0)
				{
					drawUnit(target, unit->getPlayer()->getId(), unit->getType(),
						currpos, spritescale);
				}
			}
		}

		drawPath(target);
	}

	void BoardWidget::calcSpriteDimensions(int boardwidth, int boardheight)
	{
		if(boardwidth > boardheight)
		{
			spritedimensions = getSize().x / boardwidth;
			singlespritescale = getSize().x / (boardwidth * 32.0);
		}
		else
		{
			spritedimensions = getSize().y / boardheight;
			singlespritescale = getSize().y / (boardheight * 32.0);
		}
	}

	void BoardWidget::drawTerrain(sf::RenderTarget& target,
		TERRAINTYPES terraintype, sf::Vector2f position, sf::Vector2f scale) const
	{
		terrainsprites[terraintype]->setPosition(position);
		terrainsprites[terraintype]->setScale(scale);
		target.draw(*terrainsprites[terraintype]);
	}

	void BoardWidget::drawUnit(sf::RenderTarget& target, int playerid,
		UNITTYPES unittype, sf::Vector2f position, sf::Vector2f scale) const
	{
		sf::Sprite* unitsprite = 0;
		if(playerid == 0)
			unitsprite = p1unitsprites[unittype];
		else
			unitsprite = p2unitsprites[unittype];
		unitsprite->setPosition(position);
		unitsprite->setScale(scale);
		target.draw(*unitsprite);
	}

	void BoardWidget::drawPath(sf::RenderTarget& target) const
	{
		if(!path)
			return;

		sf::CircleShape circle(spritedimensions);
		circle.setOrigin(spritedimensions, spritedimensions);
		circle.scale(0.2, 0.2);
		circle.setFillColor(sf::Color::Red);

		for(auto square : *path)
		{
			circle.setPosition(
				spritedimensions * square->getXPosition() + 0.5 * spritedimensions,
				spritedimensions * square->getYPosition() + 0.5 * spritedimensions
			);
			target.draw(circle);
		}
	}

	void BoardWidget::moveUnitIngame()
	{
		Cursor* cursor = Cursor::getCursor();
		Cursor* childcursor = cursor->getChild();

		if(childcursor)
		{
			Unit* unit1 = board->getSquare(cursor->getPosition().x, cursor->getPosition().y)->getUnit();
			int unit1hp = unit1->getHP();
			Unit* unit2 = board->getSquare(childcursor->getPosition().x, childcursor->getPosition().y)->getUnit();
			int unit2hp;

			if(unit2)
				unit2hp = unit2->getHP();

			int moveresult = engine->moveUnitIngame(cursor->getPosition().x, cursor->getPosition().y,
				childcursor->getPosition().x, childcursor->getPosition().y);
			printf("moveresult: %i\n", moveresult);
			if(moveresult == 0 || moveresult == -9 || moveresult == -8 || moveresult == -11)
			{
				// Display damage numbers
				if(moveresult == -9 || moveresult == -8 || moveresult == -11)
				{
					DamageNumber* dm;
					sf::Vector2f pos;

					// First DMG number
					pos.x = cursor->getPosition().x * spritedimensions;
					pos.y = cursor->getPosition().y * spritedimensions + spritedimensions * 0.2;
					dm = new DamageNumber(unit1->getHP() - unit1hp, pos);
					// Second DMG number
					pos.x = childcursor->getPosition().x * spritedimensions;
					pos.y = childcursor->getPosition().y * spritedimensions + spritedimensions * 0.2;
					dm = new DamageNumber(unit2->getHP() - unit2hp, pos);
				}

				// Resetting cursors
				cursor->setPosition(childcursor->getPosition());
				cursor->despawnChild();
			}
		}
	}

	void BoardWidget::updateCursor()
	{
		// Calculate on which field the mouse cursor is placed.
		sf::Vector2i mousePosition = sf::Mouse::getPosition(*window);
		sf::Vector2i newCursorPos;

		newCursorPos.x = floor( ((float)mousePosition.x) / spritedimensions );
		newCursorPos.y = floor( ((float)mousePosition.y) / spritedimensions );

		// Boarder checks
		if(newCursorPos.x < 0)
			newCursorPos.x = 0;
		else if(newCursorPos.x > board->getWidth())
			newCursorPos.x = board->getWidth();

		if(newCursorPos.y < 0)
			newCursorPos.y = 0;
		else if(newCursorPos.y > board->getHeight())
			newCursorPos.y = board->getHeight();

		if(!Cursor::getCursor()->getChild())
			Cursor::getCursor()->setPosition(newCursorPos);
		else
		{
			Cursor::getCursor()->getChild()->setPosition(newCursorPos);

			if(engine->getStatus() == EES_RUNNING)
			{
				// Update path
				if(path)
					delete path;
				path = engine->findPath(
					Coordinates(Cursor::getCursor()->getPosition().x, Cursor::getCursor()->getPosition().y),
					Coordinates(newCursorPos.x, newCursorPos.y)
				);
			}
		}
	}

	void BoardWidget::leftClicked()
	{
		Cursor* cursor = Cursor::getCursor();
		Cursor* childcursor = cursor->getChild();
		Square* cursorsquare = board->getSquare(cursor->getPosition().x, cursor->getPosition().y);

		// Depploy unit / terrain by calling deploywindow methods.
		if(engine->getStatus() == EES_PREPARE)
		{
			if(childcursor)
			{
				deploywindow->moveUnit();
			}
			else if(cursorsquare->getUnit())
			{
				cursor->spawnChild();
			}
			else
			{
				printf("boardwidget leftclicked pre placeEntity (deploywindow=%p)\n", deploywindow);
				deploywindow->placeEntity();
			}
		}
		// Ingame actions.
		// TODO: Following code is just a copy&paste of GuiHandler::HandleEvent() code. Find a better solution
		// for this code duplication...
		else
		{
			if(cursorsquare->getUnit() && !childcursor)
			{
				cursor->spawnChild();
			}
			// Move a unit
			else if(childcursor)
			{
				this->moveUnitIngame();
				if(path)
				{
					delete path;
					path = 0;
				}
			}
		}
	} // BoardWidget::leftClicked();

	void BoardWidget::rightClicked()
	{
		Cursor* cursor = Cursor::getCursor();
		Cursor* childcursor = cursor->getChild();
		if(childcursor)
		{
			cursor->setPosition(childcursor->getPosition());
			cursor->despawnChild();
		}
		if(path)
		{
			delete path;
			path = 0;
		}
	}

	void BoardWidget::keyPressed(const sf::Event& event)
	{
		qrw::Cursor* cursor = qrw::Cursor::getCursor();
		qrw::Cursor* childcursor = cursor->getChild();

		if(event.key.code == sf::Keyboard::Up)
			cursor->move(0, -1);
		else if(event.key.code == sf::Keyboard::Down)
			cursor->move(0, 1);
		else if(event.key.code == sf::Keyboard::Right)
			cursor->move(1, 0);
		else if(event.key.code == sf::Keyboard::Left)
			cursor->move(-1, 0);
		else if(event.key.code == sf::Keyboard::Escape)
			cursor->despawnChild();
		else if(event.key.code == sf::Keyboard::Return)
		{
			if(engine->getStatus() == EES_PREPARE)
			{
				// Check if a new unit is placed or a unit is moved.
				// A unit is moved if cursor has a child (to point to destination)
				// or there is a unit under cursor.
				Square* cursorsquare = engine->getBoard()->getSquare(cursor->getPosition().x,
						cursor->getPosition().y);
				if (cursor->getChild() != NULL)
				{
					deploywindow->moveUnit();
				}
				else if(cursorsquare->getUnit() != NULL)
				{
					cursor->spawnChild();
				}
				else
				{
					deploywindow->placeEntity();
				}
			}
			else if(childcursor == 0)
			{
				cursor->spawnChild();
			}
			else if(childcursor != 0)
			{
				this->moveUnitIngame();
			}
		}
	}
}<commit_msg>qrw::BoardWidget: Path is now only deleted on left click if movement was successful.<commit_after>#include "gui/boardwidget.hpp"

#include <cmath>

#include <SFML/Graphics/Vertex.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <SFML/Graphics/PrimitiveType.hpp>
#include <SFML/Graphics/RenderTarget.hpp>

#include <SFML/Graphics/CircleShape.hpp>
#include <SFML/Graphics/Color.hpp>

#include <iostream>
#include <stdio.h>

#include "engine/engine.hpp"
#include "engine/player.hpp"
#include "engine/pathfinding/path.hpp"
#include "gui/guihandler.hpp"
#include "gui/cursor.hpp"
#include "gui/damagenumber.hpp"

namespace qrw
{
	BoardWidget::BoardWidget(GuiHandler* guihandler, Engine* engine, float width, float height)
	: Widget(guihandler->getRenderWindow(), width, height),
	  board(0),
	  engine(engine),
	  spritedimensions(0.0),
	  singlespritescale(0.0),
	  path(0),
	  deploywindow(guihandler->getDeployWindow())
	{
		printf("boardrenderer position: x=%f / y=%f\n", getGlobalBounds().left, getGlobalBounds().top);
		printf("boardrenderer size: w=%f / h=%f\n", getSize().x, getSize().y);

		// Create required sprites.
		TextureManager* texturemanager = TextureManager::getInstance();

		plainsquare = new sf::Sprite(*texturemanager->getTexture("plainsquare"));
		terrainsprites[ET_WOOD] = new sf::Sprite(*texturemanager->getTexture("wood"));
		terrainsprites[ET_HILL] = new sf::Sprite(*texturemanager->getTexture("hill"));
		terrainsprites[ET_WALL] = new sf::Sprite(*texturemanager->getTexture("wall"));
		p1unitsprites[EUT_SWORDMAN] = new sf::Sprite(*texturemanager->getTexture("p1swordman"));
		p1unitsprites[EUT_ARCHER] = new sf::Sprite(*texturemanager->getTexture("p1archer"));
		p1unitsprites[EUT_SPEARMAN] = new sf::Sprite(*texturemanager->getTexture("p1spearman"));
		p2unitsprites[EUT_SWORDMAN] = new sf::Sprite(*texturemanager->getTexture("p2swordman"));
		p2unitsprites[EUT_ARCHER] = new sf::Sprite(*texturemanager->getTexture("p2archer"));
		p2unitsprites[EUT_SPEARMAN] = new sf::Sprite(*texturemanager->getTexture("p2spearman"));

		signalmousemoved.connect(std::bind(&BoardWidget::updateCursor, this));
		signalmouseentered.connect(std::bind(&BoardWidget::updateCursor, this));
		signalclicked.connect(std::bind(&BoardWidget::leftClicked, this));
		signalrightclicked.connect(std::bind(&BoardWidget::rightClicked, this));
		signalkeypressed.connect(std::bind(&BoardWidget::keyPressed, this, std::placeholders::_1));
	}

	BoardWidget::~BoardWidget()
	{
		delete plainsquare;
	}

	void BoardWidget::setBoard(Board* board)
	{
		this->board = board;
		calcSpriteDimensions(board->getWidth(), board->getHeight());
	}

	void BoardWidget::draw(sf::RenderTarget &target, sf::RenderStates states) const
	{
		sf::Vector2f targetsize = target.getView().getSize();
		targetsize.x -= 180.0;
		int width = board->getWidth();
		int height = board->getHeight();

		sf::Vector2f spritescale(singlespritescale, singlespritescale);
		sf::VertexArray vertices(sf::Lines, 0);
		Square *square = 0;
		Unit *unit = 0;
		Terrain *terrain = 0;
		sf::Vector2f currpos;

		sf::Vector2i cursorpos = Cursor::getCursor()->getPosition();
		sf::Vector2i childcursorpos(-1, -1);

		if(Cursor::getCursor()->getChild() != 0)
		{
			childcursorpos.x = Cursor::getCursor()->getChild()->getPosition().x;
			childcursorpos.y = Cursor::getCursor()->getChild()->getPosition().y;
		}

		for(int i = 0; i < width; ++i)
		{
			for(int j = 0; j < height; ++j)
			{
				currpos.x = i * spritedimensions;
				currpos.y = j * spritedimensions;

				plainsquare->setPosition(currpos);
				plainsquare->setScale(spritescale);
				target.draw(*plainsquare);

				square = board->getSquare(i, j);
				terrain = square->getTerrain();
				unit = square->getUnit();
				// Render cursor
				if(cursorpos.x == i && cursorpos.y == j)
					Cursor::getCursor()->draw(target, currpos, spritedimensions);
				if(childcursorpos.x == i && childcursorpos.y == j)
					Cursor::getCursor()->drawChild(target, currpos, spritedimensions);

				// Render Terrain
				if(terrain != 0)
				{
					drawTerrain(target, terrain->getType(), currpos, spritescale);
				}
				// Render Units
				if(unit != 0)
				{
					drawUnit(target, unit->getPlayer()->getId(), unit->getType(),
						currpos, spritescale);
				}
			}
		}

		drawPath(target);
	}

	void BoardWidget::calcSpriteDimensions(int boardwidth, int boardheight)
	{
		if(boardwidth > boardheight)
		{
			spritedimensions = getSize().x / boardwidth;
			singlespritescale = getSize().x / (boardwidth * 32.0);
		}
		else
		{
			spritedimensions = getSize().y / boardheight;
			singlespritescale = getSize().y / (boardheight * 32.0);
		}
	}

	void BoardWidget::drawTerrain(sf::RenderTarget& target,
		TERRAINTYPES terraintype, sf::Vector2f position, sf::Vector2f scale) const
	{
		terrainsprites[terraintype]->setPosition(position);
		terrainsprites[terraintype]->setScale(scale);
		target.draw(*terrainsprites[terraintype]);
	}

	void BoardWidget::drawUnit(sf::RenderTarget& target, int playerid,
		UNITTYPES unittype, sf::Vector2f position, sf::Vector2f scale) const
	{
		sf::Sprite* unitsprite = 0;
		if(playerid == 0)
			unitsprite = p1unitsprites[unittype];
		else
			unitsprite = p2unitsprites[unittype];
		unitsprite->setPosition(position);
		unitsprite->setScale(scale);
		target.draw(*unitsprite);
	}

	void BoardWidget::drawPath(sf::RenderTarget& target) const
	{
		if(!path)
			return;

		sf::CircleShape circle(spritedimensions);
		circle.setOrigin(spritedimensions, spritedimensions);
		circle.scale(0.2, 0.2);
		circle.setFillColor(sf::Color::Red);

		for(auto square : *path)
		{
			circle.setPosition(
				spritedimensions * square->getXPosition() + 0.5 * spritedimensions,
				spritedimensions * square->getYPosition() + 0.5 * spritedimensions
			);
			target.draw(circle);
		}
	}

	void BoardWidget::moveUnitIngame()
	{
		Cursor* cursor = Cursor::getCursor();
		Cursor* childcursor = cursor->getChild();

		if(childcursor)
		{
			Unit* unit1 = board->getSquare(cursor->getPosition().x, cursor->getPosition().y)->getUnit();
			int unit1hp = unit1->getHP();
			Unit* unit2 = board->getSquare(childcursor->getPosition().x, childcursor->getPosition().y)->getUnit();
			int unit2hp;

			if(unit2)
				unit2hp = unit2->getHP();

			int moveresult = engine->moveUnitIngame(cursor->getPosition().x, cursor->getPosition().y,
				childcursor->getPosition().x, childcursor->getPosition().y);
			printf("moveresult: %i\n", moveresult);
			if(moveresult == 0 || moveresult == -9 || moveresult == -8 || moveresult == -11)
			{
				// Display damage numbers
				if(moveresult == -9 || moveresult == -8 || moveresult == -11)
				{
					DamageNumber* dm;
					sf::Vector2f pos;

					// First DMG number
					pos.x = cursor->getPosition().x * spritedimensions;
					pos.y = cursor->getPosition().y * spritedimensions + spritedimensions * 0.2;
					dm = new DamageNumber(unit1->getHP() - unit1hp, pos);
					// Second DMG number
					pos.x = childcursor->getPosition().x * spritedimensions;
					pos.y = childcursor->getPosition().y * spritedimensions + spritedimensions * 0.2;
					dm = new DamageNumber(unit2->getHP() - unit2hp, pos);
				}

				// Resetting cursors
				cursor->setPosition(childcursor->getPosition());
				cursor->despawnChild();
				// Reset path
				if(path)
				{
					delete path;
					path = 0;
				}
			}
		}
	}

	void BoardWidget::updateCursor()
	{
		// Calculate on which field the mouse cursor is placed.
		sf::Vector2i mousePosition = sf::Mouse::getPosition(*window);
		sf::Vector2i newCursorPos;

		newCursorPos.x = floor( ((float)mousePosition.x) / spritedimensions );
		newCursorPos.y = floor( ((float)mousePosition.y) / spritedimensions );

		// Boarder checks
		if(newCursorPos.x < 0)
			newCursorPos.x = 0;
		else if(newCursorPos.x > board->getWidth())
			newCursorPos.x = board->getWidth();

		if(newCursorPos.y < 0)
			newCursorPos.y = 0;
		else if(newCursorPos.y > board->getHeight())
			newCursorPos.y = board->getHeight();

		if(!Cursor::getCursor()->getChild())
			Cursor::getCursor()->setPosition(newCursorPos);
		else
		{
			Cursor::getCursor()->getChild()->setPosition(newCursorPos);

			if(engine->getStatus() == EES_RUNNING)
			{
				// Update path
				if(path)
					delete path;
				path = engine->findPath(
					Coordinates(Cursor::getCursor()->getPosition().x, Cursor::getCursor()->getPosition().y),
					Coordinates(newCursorPos.x, newCursorPos.y)
				);
			}
		}
	}

	void BoardWidget::leftClicked()
	{
		Cursor* cursor = Cursor::getCursor();
		Cursor* childcursor = cursor->getChild();
		Square* cursorsquare = board->getSquare(cursor->getPosition().x, cursor->getPosition().y);

		// Depploy unit / terrain by calling deploywindow methods.
		if(engine->getStatus() == EES_PREPARE)
		{
			if(childcursor)
			{
				deploywindow->moveUnit();
			}
			else if(cursorsquare->getUnit())
			{
				cursor->spawnChild();
			}
			else
			{
				printf("boardwidget leftclicked pre placeEntity (deploywindow=%p)\n", deploywindow);
				deploywindow->placeEntity();
			}
		}
		// Ingame actions.
		// TODO: Following code is just a copy&paste of GuiHandler::HandleEvent() code. Find a better solution
		// for this code duplication...
		else
		{
			if(cursorsquare->getUnit() && !childcursor)
			{
				cursor->spawnChild();
			}
			// Move a unit
			else if(childcursor)
			{
				this->moveUnitIngame();
			}
		}
	} // BoardWidget::leftClicked();

	void BoardWidget::rightClicked()
	{
		Cursor* cursor = Cursor::getCursor();
		Cursor* childcursor = cursor->getChild();
		if(childcursor)
		{
			cursor->setPosition(childcursor->getPosition());
			cursor->despawnChild();
		}
		if(path)
		{
			delete path;
			path = 0;
		}
	}

	void BoardWidget::keyPressed(const sf::Event& event)
	{
		qrw::Cursor* cursor = qrw::Cursor::getCursor();
		qrw::Cursor* childcursor = cursor->getChild();

		if(event.key.code == sf::Keyboard::Up)
			cursor->move(0, -1);
		else if(event.key.code == sf::Keyboard::Down)
			cursor->move(0, 1);
		else if(event.key.code == sf::Keyboard::Right)
			cursor->move(1, 0);
		else if(event.key.code == sf::Keyboard::Left)
			cursor->move(-1, 0);
		else if(event.key.code == sf::Keyboard::Escape)
			cursor->despawnChild();
		else if(event.key.code == sf::Keyboard::Return)
		{
			if(engine->getStatus() == EES_PREPARE)
			{
				// Check if a new unit is placed or a unit is moved.
				// A unit is moved if cursor has a child (to point to destination)
				// or there is a unit under cursor.
				Square* cursorsquare = engine->getBoard()->getSquare(cursor->getPosition().x,
						cursor->getPosition().y);
				if (cursor->getChild() != NULL)
				{
					deploywindow->moveUnit();
				}
				else if(cursorsquare->getUnit() != NULL)
				{
					cursor->spawnChild();
				}
				else
				{
					deploywindow->placeEntity();
				}
			}
			else if(childcursor == 0)
			{
				cursor->spawnChild();
			}
			else if(childcursor != 0)
			{
				this->moveUnitIngame();
			}
		}
	}
}<|endoftext|>


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

// mapnik
#if defined(HAVE_JPEG)
#include <mapnik/jpeg_io.hpp>
#endif

#include <mapnik/image_util.hpp>
#include <mapnik/image_util_jpeg.hpp>
#include <mapnik/image.hpp>
#include <mapnik/image_any.hpp>
#include <mapnik/image_view.hpp>
#include <mapnik/util/conversions.hpp>

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

// stl
#include <string>
#include <iostream>

namespace mapnik
{

jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t):
    stream_(stream), t_(t) {}

template <typename T>
void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & stream)
{
#if defined(HAVE_JPEG)
    int quality = 85;
    std::string val = t.substr(4);
    if (!val.empty())
    {
        if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100)
        {
            throw ImageWriterException("invalid jpeg quality: '" + val + "'");
        }
    }
    save_as_jpeg(stream, quality, image);
#else
    throw ImageWriterException("jpeg output is not enabled in your build of Mapnik");
#endif
}

template<>
void jpeg_saver::operator()<image_rgba8> (image_rgba8 const& image) const
{
    process_rgba8_jpeg(image, t_, stream_);
}

template<>
void jpeg_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const
{
    process_rgba8_jpeg(image, t_, stream_);
}

template<>
void jpeg_saver::operator()<image_null> (image_null const& image) const
{
    throw ImageWriterException("Can not save a null image to jpeg");
}

template <typename T>
void jpeg_saver::operator() (T const& image) const
{
    throw ImageWriterException("Mapnik does not support jpeg grayscale images");
}

template void jpeg_saver::operator()<image_rgba8> (image_rgba8 const& image) const;
template void jpeg_saver::operator()<image_gray8> (image_gray8 const& image) const;
template void jpeg_saver::operator()<image_gray8s> (image_gray8s const& image) const;
template void jpeg_saver::operator()<image_gray16> (image_gray16 const& image) const;
template void jpeg_saver::operator()<image_gray16s> (image_gray16s const& image) const;
template void jpeg_saver::operator()<image_gray32> (image_gray32 const& image) const;
template void jpeg_saver::operator()<image_gray32s> (image_gray32s const& image) const;
template void jpeg_saver::operator()<image_gray32f> (image_gray32f const& image) const;
template void jpeg_saver::operator()<image_gray64> (image_gray64 const& image) const;
template void jpeg_saver::operator()<image_gray64s> (image_gray64s const& image) const;
template void jpeg_saver::operator()<image_gray64f> (image_gray64f const& image) const;
template void jpeg_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const;
template void jpeg_saver::operator()<image_view_gray8> (image_view_gray8 const& image) const;
template void jpeg_saver::operator()<image_view_gray8s> (image_view_gray8s const& image) const;
template void jpeg_saver::operator()<image_view_gray16> (image_view_gray16 const& image) const;
template void jpeg_saver::operator()<image_view_gray16s> (image_view_gray16s const& image) const;
template void jpeg_saver::operator()<image_view_gray32> (image_view_gray32 const& image) const;
template void jpeg_saver::operator()<image_view_gray32s> (image_view_gray32s const& image) const;
template void jpeg_saver::operator()<image_view_gray32f> (image_view_gray32f const& image) const;
template void jpeg_saver::operator()<image_view_gray64> (image_view_gray64 const& image) const;
template void jpeg_saver::operator()<image_view_gray64s> (image_view_gray64s const& image) const;
template void jpeg_saver::operator()<image_view_gray64f> (image_view_gray64f const& image) const;

} // end ns
<commit_msg>A fix for jpeg saving, as it wasn't properly dealing with a colon for saving with quality.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#if defined(HAVE_JPEG)
#include <mapnik/jpeg_io.hpp>
#endif

#include <mapnik/image_util.hpp>
#include <mapnik/image_util_jpeg.hpp>
#include <mapnik/image.hpp>
#include <mapnik/image_any.hpp>
#include <mapnik/image_view.hpp>
#include <mapnik/util/conversions.hpp>

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

// stl
#include <string>
#include <iostream>

namespace mapnik
{

jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t):
    stream_(stream), t_(t) {}

template <typename T>
void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & stream)
{
#if defined(HAVE_JPEG)
    int quality = 85;
    std::string val = t.substr(5);
    if (!val.empty())
    {
        if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100)
        {
            throw ImageWriterException("invalid jpeg quality: '" + val + "'");
        }
    }
    save_as_jpeg(stream, quality, image);
#else
    throw ImageWriterException("jpeg output is not enabled in your build of Mapnik");
#endif
}

template<>
void jpeg_saver::operator()<image_rgba8> (image_rgba8 const& image) const
{
    process_rgba8_jpeg(image, t_, stream_);
}

template<>
void jpeg_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const
{
    process_rgba8_jpeg(image, t_, stream_);
}

template<>
void jpeg_saver::operator()<image_null> (image_null const& image) const
{
    throw ImageWriterException("Can not save a null image to jpeg");
}

template <typename T>
void jpeg_saver::operator() (T const& image) const
{
    throw ImageWriterException("Mapnik does not support jpeg grayscale images");
}

template void jpeg_saver::operator()<image_rgba8> (image_rgba8 const& image) const;
template void jpeg_saver::operator()<image_gray8> (image_gray8 const& image) const;
template void jpeg_saver::operator()<image_gray8s> (image_gray8s const& image) const;
template void jpeg_saver::operator()<image_gray16> (image_gray16 const& image) const;
template void jpeg_saver::operator()<image_gray16s> (image_gray16s const& image) const;
template void jpeg_saver::operator()<image_gray32> (image_gray32 const& image) const;
template void jpeg_saver::operator()<image_gray32s> (image_gray32s const& image) const;
template void jpeg_saver::operator()<image_gray32f> (image_gray32f const& image) const;
template void jpeg_saver::operator()<image_gray64> (image_gray64 const& image) const;
template void jpeg_saver::operator()<image_gray64s> (image_gray64s const& image) const;
template void jpeg_saver::operator()<image_gray64f> (image_gray64f const& image) const;
template void jpeg_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const;
template void jpeg_saver::operator()<image_view_gray8> (image_view_gray8 const& image) const;
template void jpeg_saver::operator()<image_view_gray8s> (image_view_gray8s const& image) const;
template void jpeg_saver::operator()<image_view_gray16> (image_view_gray16 const& image) const;
template void jpeg_saver::operator()<image_view_gray16s> (image_view_gray16s const& image) const;
template void jpeg_saver::operator()<image_view_gray32> (image_view_gray32 const& image) const;
template void jpeg_saver::operator()<image_view_gray32s> (image_view_gray32s const& image) const;
template void jpeg_saver::operator()<image_view_gray32f> (image_view_gray32f const& image) const;
template void jpeg_saver::operator()<image_view_gray64> (image_view_gray64 const& image) const;
template void jpeg_saver::operator()<image_view_gray64s> (image_view_gray64s const& image) const;
template void jpeg_saver::operator()<image_view_gray64f> (image_view_gray64f const& image) const;

} // end ns
<|endoftext|>


<commit_before>#include <team_diana_lib/logging/logging.h>

#include <ros/ros.h>

void Td::ros_info(const std::string& msg) {
  ROS_INFO(msg.c_str());
}

void Td::ros_warn(const std::string& msg) {
  ROS_WARN(msg.c_str());
}

void Td::ros_error(const std::string& msg) {
  ROS_ERROR(msg.c_str());
}

void Td::ros_fatal(const std::string& msg) {
  ROS_FATAL(msg.c_str());
}
<commit_msg>Fixed uncontrolled format string bug<commit_after>#include <team_diana_lib/logging/logging.h>

#include <ros/ros.h>

void Td::ros_info(const std::string& msg) {
	ROS_INFO("%s", msg.c_str());
}

void Td::ros_warn(const std::string& msg) {
  ROS_WARN("%s", msg.c_str());
}

void Td::ros_error(const std::string& msg) {
  ROS_ERROR("%s", msg.c_str());
}

void Td::ros_fatal(const std::string& msg) {
	ROS_FATAL("%s", msg.c_str());
}
<|endoftext|>


<commit_before><commit_msg>Fixed compilation error on clang-3.5<commit_after><|endoftext|>


<commit_before>#if TZ_OGL
#include "tz/core/containers/basic_list.hpp"
#include "tz/core/report.hpp"
#include "tz/core/profiling/zone.hpp"
#include "tz/gl/impl/backend/ogl2/tz_opengl.hpp"

namespace tz::gl::ogl2
{
	tz::BasicList<OGLStringView> get_supported_ogl_extensions();

	bool initialised = false;

	void debug_callback([[maybe_unused]] GLenum source, [[maybe_unused]] GLenum type, [[maybe_unused]] GLuint id, GLenum severity, [[maybe_unused]] GLsizei length, const GLchar* message, [[maybe_unused]] const void* userdata)
	{
		if(type == GL_DEBUG_TYPE_ERROR && (severity & (GL_DEBUG_SEVERITY_HIGH | GL_DEBUG_SEVERITY_MEDIUM)))
		{
			tz_error("OpenGL Error: %s", message);
		}
	}

	void initialise()
	{
		TZ_PROFZONE("OpenGL Backend - Backend Initialise", TZ_PROFCOL_RED);
		tz_assert(!initialised, "Already initialised OpenGL but trying to do it again. Please submit a bug report.");
		int res = gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress));
		#if TZ_PROFILE
			TracyGpuContext;
		#endif // TZ_PROFILE
		tz_assert(res != 0, "GLAD failed to load");
		#if TZ_DEBUG
			glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
			glDebugMessageCallback(debug_callback, nullptr);
		#endif
		if(!supports_bindless_textures())
		{
			tz_warning_report("The OpenGL backend implicitly uses bindless textures under-the-hood, and initialisation has just detected that the extension `GL_ARB_bindless_texture` is not available. The application will most certainly crash if you try to use OGL textures.");
		}
		tz_report("OpenGL v%u.%u Initialised", ogl_version.major, ogl_version.minor);
		initialised = true;
	}

	void terminate()
	{
		tz_assert(initialised, "Not initialised when trying to terminate OpenGL. Please submit a bug report.");
		initialised = false;
		tz_report("OpenGL v%u.%u Terminated", ogl_version.major, ogl_version.minor);
	}

	bool is_initialised()
	{
		return initialised;
	}

	tz::BasicList<OGLStringView> get_supported_ogl_extensions()
	{
		GLint extension_count;
		glGetIntegerv(GL_NUM_EXTENSIONS, &extension_count);
		tz::BasicList<OGLStringView> exts;
		exts.resize(extension_count);
		for(std::size_t i = 0; std::cmp_less(i, extension_count); i++)
		{
			exts[i] = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(i)));
		}
		return exts;
	}

	bool supports_bindless_textures()
	{
		return get_supported_ogl_extensions().contains("GL_ARB_bindless_texture");
	}
}

#endif // TZ_OGL
<commit_msg>* OGL: Change bindful alert warning as it no longer guarantees a crash, but instead gives you shitty behaviour. A small upgrade? I only did this to stop the CI from crashing because dbgui uses it. This also means in theory the demos/tests can start using imageresources<commit_after>#if TZ_OGL
#include "tz/core/containers/basic_list.hpp"
#include "tz/core/report.hpp"
#include "tz/core/profiling/zone.hpp"
#include "tz/gl/impl/backend/ogl2/tz_opengl.hpp"

namespace tz::gl::ogl2
{
	tz::BasicList<OGLStringView> get_supported_ogl_extensions();

	bool initialised = false;

	void debug_callback([[maybe_unused]] GLenum source, [[maybe_unused]] GLenum type, [[maybe_unused]] GLuint id, GLenum severity, [[maybe_unused]] GLsizei length, const GLchar* message, [[maybe_unused]] const void* userdata)
	{
		if(type == GL_DEBUG_TYPE_ERROR && (severity & (GL_DEBUG_SEVERITY_HIGH | GL_DEBUG_SEVERITY_MEDIUM)))
		{
			tz_error("OpenGL Error: %s", message);
		}
	}

	void initialise()
	{
		TZ_PROFZONE("OpenGL Backend - Backend Initialise", TZ_PROFCOL_RED);
		tz_assert(!initialised, "Already initialised OpenGL but trying to do it again. Please submit a bug report.");
		int res = gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress));
		#if TZ_PROFILE
			TracyGpuContext;
		#endif // TZ_PROFILE
		tz_assert(res != 0, "GLAD failed to load");
		#if TZ_DEBUG
			glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
			glDebugMessageCallback(debug_callback, nullptr);
		#endif
		if(!supports_bindless_textures())
		{
			tz_warning_report("The OpenGL backend prefers using bindless textures under-the-hood. Unfortunately, the bindless textures extension `GL_ARB_bindltess_texture` is unavailable on this implementation. Renderers will fallback to old-style OpenGL uniforms for image resources, although this behaviour is unreliable and could be removed at any point.");
		}
		tz_report("OpenGL v%u.%u %sInitialised", ogl_version.major, ogl_version.minor, supports_bindless_textures() ? "" : "(Bindful) ");
		initialised = true;
	}

	void terminate()
	{
		tz_assert(initialised, "Not initialised when trying to terminate OpenGL. Please submit a bug report.");
		initialised = false;
		tz_report("OpenGL v%u.%u Terminated", ogl_version.major, ogl_version.minor);
	}

	bool is_initialised()
	{
		return initialised;
	}

	tz::BasicList<OGLStringView> get_supported_ogl_extensions()
	{
		GLint extension_count;
		glGetIntegerv(GL_NUM_EXTENSIONS, &extension_count);
		tz::BasicList<OGLStringView> exts;
		exts.resize(extension_count);
		for(std::size_t i = 0; std::cmp_less(i, extension_count); i++)
		{
			exts[i] = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(i)));
		}
		return exts;
	}

	bool supports_bindless_textures()
	{
		return get_supported_ogl_extensions().contains("GL_ARB_bindless_texture");
	}
}

#endif // TZ_OGL
<|endoftext|>