<commit_before>#include "dbg_helper.h"
#include <memory>
#include <sstream>
#include <TlHelp32.h>
#pragma comment(lib, "DbgHelp.lib")

namespace {

std::string GetLastErrMsg() {
	DWORD err = GetLastError();
	LPVOID msg_buf;
	std::string ret;
	std::ostringstream ss;
	ss << err;
	ret.append("[").append(ss.str()).append("] ");
	if (0 == FormatMessageA(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		reinterpret_cast<char*>(&msg_buf), 0, NULL))
		return ret;
	ret.append(reinterpret_cast<char*>(msg_buf));
	LocalFree(msg_buf);
	return ret;
}

}

namespace tracer {

std::string DbgHelper::GetSymSearchPath_() {
	std::string path(".;");
	const std::size_t buf_size = 4096;
	char buf[buf_size];

	if (GetCurrentDirectoryA(buf_size, buf) > 0)
		path.append(buf).append(";");

	if (GetModuleFileNameA(NULL, buf, buf_size) > 0) {
		for (char *p = (buf + strlen(buf) - 1); p >= buf; --p) {
			if ((*p == '\\') || (*p == '/') || (*p == ';')) {
				*p = '\0';
				break;
			}
		}
		if (strlen(buf) > 0)
			path.append(buf).append(";");
	}

	if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", buf, buf_size) > 0)
		path.append(buf).append(";");

	if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", buf, buf_size) > 0)
		path.append(buf).append(";");

	if (GetEnvironmentVariableA("SYSTEMROOT", buf, buf_size) > 0)
		path.append(buf).append(";").append(buf).append("\\system32").append(";");

	return path;
}

void DbgHelper::LoadModules_() {
	MODULEENTRY32 me = {sizeof(me)};
	HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());

	if (INVALID_HANDLE_VALUE == snap)
		throw std::runtime_error("CreateToolhelp32Snapshot fail " + GetLastErrMsg());

	bool keep_going = !!Module32First(snap, &me);
	while (keep_going) {
		if ((0 == SymLoadModuleEx(GetCurrentProcess(), NULL, me.szExePath, me.szModule,
				reinterpret_cast<DWORD64>(me.modBaseAddr), me.modBaseSize, NULL, 0))
			&& (ERROR_SUCCESS != GetLastError()))
			throw std::runtime_error("SymLoadModuleEx fail " + GetLastErrMsg());
		keep_going = !!Module32Next(snap, &me);
	}
	CloseHandle(snap);
}

void DbgHelper::Init_() {
	std::string path = GetSymSearchPath_();
	std::lock_guard<std::mutex> l(lock_);

	if (FALSE == SymInitialize(GetCurrentProcess(), path.c_str(), FALSE))
		throw std::runtime_error("SymInitialize fail " + GetLastErrMsg());

	DWORD options = SymGetOptions();
	options |= SYMOPT_LOAD_LINES;
	options |= SYMOPT_FAIL_CRITICAL_ERRORS;
	SymSetOptions(options);

	LoadModules_();
}

bool DbgHelper::Cleanup_() {
	std::lock_guard<std::mutex> l(lock_);
	return !!SymCleanup(GetCurrentProcess());
}

void DbgHelper::AllocSymBuffer_( std::size_t size ) {
	if (sym_buffer_)
		delete sym_buffer_;
	sym_buffer_ = static_cast<PSYMBOL_INFO>(malloc(sizeof(SYMBOL_INFO) + size));
	sym_buffer_->SizeOfStruct = sizeof(SYMBOL_INFO);
	sym_buffer_->MaxNameLen = size;
}

DbgHelper::DbgHelper() {
	Init_();
	sym_buffer_ = nullptr;
	AllocSymBuffer_(1024);

	ZeroMemory(&line_info_, sizeof(line_info_));
	line_info_.SizeOfStruct = sizeof(line_info_);
}

DbgHelper::~DbgHelper() {
	Cleanup_();
}

/*!
Ч`context`ʱ, ൱`begin()`; дߴ`nullptr`ʱ൱`end()`
\param [in] context Ҫջ߳
\return ջĵ
*/
tracer::StackWalkIterator DbgHelper::StackWalk( CONTEXT *context /*= nullptr*/ ) {
	return StackWalkIterator(context, lock_);
}

std::string DbgHelper::GetSymbolName( DWORD64 addr ) {
	std::lock_guard<std::mutex> l(lock_);
	if (!SymFromAddr(GetCurrentProcess(), addr, NULL, sym_buffer_))
		throw std::runtime_error("SymFromAddr failed " + GetLastErrMsg());
	return sym_buffer_->Name;
}

std::string DbgHelper::UnDecorateSymbolName( const std::string symbol_name, DWORD flag /*= UNDNAME_COMPLETE*/ ) {
	std::lock_guard<std::mutex> l(lock_);
	std::size_t size = 1024;
	std::unique_ptr<char> und_name(new char[size]);
	if (!::UnDecorateSymbolName(symbol_name.c_str(), und_name.get(), size, flag))
		throw std::runtime_error("UnDecorateSymbolName failed " + GetLastErrMsg());
	std::string ret(und_name.get());
	return ret;
}

std::string DbgHelper::GetFileName( DWORD64 addr ) {
	std::lock_guard<std::mutex> l(lock_);
	DWORD displacement;
	if (!SymGetLineFromAddr64(GetCurrentProcess(), addr, &displacement, &line_info_))
		return "<unknown>";
	return line_info_.FileName;
}

DWORD DbgHelper::GetLine( DWORD64 addr ) {
	std::lock_guard<std::mutex> l(lock_);
	DWORD displacement;
	if (!SymGetLineFromAddr64(GetCurrentProcess(), addr, &displacement, &line_info_))
		return 0;
	return line_info_.LineNumber;
}

StackWalkIterator::StackWalkIterator( CONTEXT *context, std::mutex &lock ) :
	context_(context),
	lock_(lock) {
	ZeroMemory(&sf_, sizeof(sf_));
	if (context_) {
		sf_.AddrPC.Offset = context_->Eip;
		sf_.AddrPC.Mode = AddrModeFlat;
		sf_.AddrFrame.Offset = context_->Ebp;
		sf_.AddrFrame.Mode = AddrModeFlat;
		sf_.AddrStack.Offset = context_->Esp;
		sf_.AddrStack.Mode = AddrModeFlat;
		if (!StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
			&sf_, context_, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
			throw std::runtime_error("StackWalk64 failed " + GetLastErrMsg());
	}

}

StackWalkIterator & StackWalkIterator::operator++() {
	if (context_)
		if (!StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
			&sf_, context_, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
			context_ = nullptr;
	return *this;
}

tracer::StackWalkIterator StackWalkIterator::operator++( int ) {
	StackWalkIterator t = *this;
	++(*this);
	return t;
}

const STACKFRAME64 & StackWalkIterator::operator*() const {
	return sf_;
}

const STACKFRAME64 * StackWalkIterator::operator->() const {
	return &sf_;
}

StackWalkIterator::operator Bool_ () const {
	return context_ ? &StackWalkIterator::CannotCompare_ : 0;
}

}	// namespace tracer<commit_msg>improve DbgHelper, now can handle arbitrary length symbol name<commit_after>#include "dbg_helper.h"
#include <memory>
#include <sstream>
#include <TlHelp32.h>
#pragma comment(lib, "DbgHelp.lib")

namespace {

std::string GetLastErrMsg() {
	DWORD err = GetLastError();
	LPVOID msg_buf;
	std::string ret;
	std::ostringstream ss;
	ss << err;
	ret.append("[").append(ss.str()).append("] ");
	if (0 == FormatMessageA(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		reinterpret_cast<char*>(&msg_buf), 0, NULL))
		return ret;
	ret.append(reinterpret_cast<char*>(msg_buf));
	LocalFree(msg_buf);
	return ret;
}

}

namespace tracer {

std::string DbgHelper::GetSymSearchPath_() {
	std::string path(".;");
	const std::size_t buf_size = 4096;
	char buf[buf_size];

	if (GetCurrentDirectoryA(buf_size, buf) > 0)
		path.append(buf).append(";");

	if (GetModuleFileNameA(NULL, buf, buf_size) > 0) {
		for (char *p = (buf + strlen(buf) - 1); p >= buf; --p) {
			if ((*p == '\\') || (*p == '/') || (*p == ';')) {
				*p = '\0';
				break;
			}
		}
		if (strlen(buf) > 0)
			path.append(buf).append(";");
	}

	if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", buf, buf_size) > 0)
		path.append(buf).append(";");

	if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", buf, buf_size) > 0)
		path.append(buf).append(";");

	if (GetEnvironmentVariableA("SYSTEMROOT", buf, buf_size) > 0)
		path.append(buf).append(";").append(buf).append("\\system32").append(";");

	return path;
}

void DbgHelper::LoadModules_() {
	MODULEENTRY32 me = {sizeof(me)};
	HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());

	if (INVALID_HANDLE_VALUE == snap)
		throw std::runtime_error("CreateToolhelp32Snapshot fail " + GetLastErrMsg());

	bool keep_going = !!Module32First(snap, &me);
	while (keep_going) {
		if ((0 == SymLoadModuleEx(GetCurrentProcess(), NULL, me.szExePath, me.szModule,
				reinterpret_cast<DWORD64>(me.modBaseAddr), me.modBaseSize, NULL, 0))
			&& (ERROR_SUCCESS != GetLastError()))
			throw std::runtime_error("SymLoadModuleEx fail " + GetLastErrMsg());
		keep_going = !!Module32Next(snap, &me);
	}
	CloseHandle(snap);
}

void DbgHelper::Init_() {
	std::string path = GetSymSearchPath_();
	std::lock_guard<std::mutex> l(lock_);

	if (FALSE == SymInitialize(GetCurrentProcess(), path.c_str(), FALSE))
		throw std::runtime_error("SymInitialize fail " + GetLastErrMsg());

	DWORD options = SymGetOptions();
	options |= SYMOPT_LOAD_LINES;
	options |= SYMOPT_FAIL_CRITICAL_ERRORS;
	SymSetOptions(options);

	LoadModules_();
}

bool DbgHelper::Cleanup_() {
	std::lock_guard<std::mutex> l(lock_);
	return !!SymCleanup(GetCurrentProcess());
}

void DbgHelper::AllocSymBuffer_( std::size_t size ) {
	if (sym_buffer_)
		delete sym_buffer_;
	sym_buffer_ = static_cast<PSYMBOL_INFO>(malloc(sizeof(SYMBOL_INFO) + size));
	sym_buffer_->SizeOfStruct = sizeof(SYMBOL_INFO);
	sym_buffer_->MaxNameLen = size;
}

DbgHelper::DbgHelper() {
	Init_();
	sym_buffer_ = nullptr;
	AllocSymBuffer_(1024);

	ZeroMemory(&line_info_, sizeof(line_info_));
	line_info_.SizeOfStruct = sizeof(line_info_);
}

DbgHelper::~DbgHelper() {
	Cleanup_();
}

/*!
Ч`context`ʱ, ൱`begin()`; дߴ`nullptr`ʱ൱`end()`
\param [in] context Ҫջ߳
\return ջĵ
*/
tracer::StackWalkIterator DbgHelper::StackWalk( CONTEXT *context /*= nullptr*/ ) {
	return StackWalkIterator(context, lock_);
}

std::string DbgHelper::GetSymbolName( DWORD64 addr ) {
	std::lock_guard<std::mutex> l(lock_);
	while (true) {
		if (!SymFromAddr(GetCurrentProcess(), addr, NULL, sym_buffer_))
			throw std::runtime_error("SymFromAddr failed " + GetLastErrMsg());
		if (sym_buffer_->NameLen < sym_buffer_->MaxNameLen)
			break;
		AllocSymBuffer_(sym_buffer_->MaxNameLen * 2);
	}
	return sym_buffer_->Name;
}

std::string DbgHelper::UnDecorateSymbolName( const std::string symbol_name, DWORD flag /*= UNDNAME_COMPLETE*/ ) {
	std::lock_guard<std::mutex> l(lock_);
	std::size_t size = 1024;
	std::unique_ptr<char> und_name(new char[size]);
	DWORD need_size;
	while (true) {
		need_size = ::UnDecorateSymbolName(symbol_name.c_str(), und_name.get(), size, flag);
		if (need_size == 0)
			throw std::runtime_error("UnDecorateSymbolName failed " + GetLastErrMsg());
		else if (need_size >= size) {
			size = need_size + 1;
			und_name.reset(new char[size]);
		} else
			break;
	}
	std::string ret(und_name.get());
	return ret;
}

std::string DbgHelper::GetFileName( DWORD64 addr ) {
	std::lock_guard<std::mutex> l(lock_);
	DWORD displacement;
	if (!SymGetLineFromAddr64(GetCurrentProcess(), addr, &displacement, &line_info_))
		return "<unknown>";
	return line_info_.FileName;
}

DWORD DbgHelper::GetLine( DWORD64 addr ) {
	std::lock_guard<std::mutex> l(lock_);
	DWORD displacement;
	if (!SymGetLineFromAddr64(GetCurrentProcess(), addr, &displacement, &line_info_))
		return 0;
	return line_info_.LineNumber;
}

StackWalkIterator::StackWalkIterator( CONTEXT *context, std::mutex &lock ) :
	context_(context),
	lock_(lock) {
	ZeroMemory(&sf_, sizeof(sf_));
	if (context_) {
		sf_.AddrPC.Offset = context_->Eip;
		sf_.AddrPC.Mode = AddrModeFlat;
		sf_.AddrFrame.Offset = context_->Ebp;
		sf_.AddrFrame.Mode = AddrModeFlat;
		sf_.AddrStack.Offset = context_->Esp;
		sf_.AddrStack.Mode = AddrModeFlat;
		if (!StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
			&sf_, context_, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
			throw std::runtime_error("StackWalk64 failed " + GetLastErrMsg());
	}

}

StackWalkIterator & StackWalkIterator::operator++() {
	if (context_)
		if (!StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
			&sf_, context_, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
			context_ = nullptr;
	return *this;
}

tracer::StackWalkIterator StackWalkIterator::operator++( int ) {
	StackWalkIterator t = *this;
	++(*this);
	return t;
}

const STACKFRAME64 & StackWalkIterator::operator*() const {
	return sf_;
}

const STACKFRAME64 * StackWalkIterator::operator->() const {
	return &sf_;
}

StackWalkIterator::operator Bool_ () const {
	return context_ ? &StackWalkIterator::CannotCompare_ : 0;
}

}	// namespace tracer<|endoftext|>


<commit_before>//This is a testing version of the BDT training code
//Author: Zhaoyuan "Maxwell" Cui
//Physics department, Unversity of Arizona

/*------------------------------------------------------*\
|This code is designed for Vector-like B pair production |
\*----------------------------------------------------- */

#include "iostream"
#include "fstream"

#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TSystem.h"
#include "TROOT.h"

#include "TMVA/Factory.h"
#include "TMVA/Tools.h"
#include "TMVA/TMVAGui.h"

int bdt_vlq()
{
  //Load the library
  TMVA::Tools::Instance();

  std::cout<<std::endl;
  std::cout<<"==>Start BDT"<<std::endl;

  TString outputFileName("BDT_VLQ_BB.root");
  TFile *outputFile=TFile::Open(outputFileName, "RECREATE");

  //Register TMVA Factory
  TMVA::Factory *factory=new TMVA::Factory("BDT_VLQ", outputFile,
					   "V:!Silent:Color:DrawProgressBar:AnalysisType=Classification");

  //Add variables that will be used for MVA training
  factory->AddVariable("mu",'F');
  factory->AddVariable("el_pt.[0]",'F');
  factory->AddVariable("mu_pt.[1]",'F');
  factory->AddVariable("jet_pt.[0]",'F');
  factory->AddVariable("met_met",'F');
  factory->AddVariable("met_phi",'F');
  factory->AddVariable("SSee_2016",'I');
  factory->AddVariable("SSem_2016",'I');
  factory->AddVariable("SSmm_2016",'I');
  factory->AddVariable("eee_2016",'I');
  factory->AddVariable("eem_2016",'I');
  factory->AddVariable("emm_2016",'I');
  factory->AddVariable("mmm_2016",'I');
  factory->AddVariable("lep_pt.[0]",'I');
  factory->AddVariable("ht",'F');
  factory->AddVariable("met_sumet",'F');
  factory->AddVariable("bjet",'I');

  //Read training data
  //
  // --- Signal
  TString fSig="../../dataPreparation/signal/normalized_BBS_M1000_302494_SSsig_deterre_Apr2017_36p1ifb_25nsTOPQ1_eLHM.root";
  TFile *inputBB=TFile::Open(fSig);
  TTree *signal=(TTree*)inputBB->Get("nominal_Loose");

  // --- Background
  TString fBkg="../../dataPreparation/background/normalized_ttW_np0_410066_SSbkg_deterre_Apr2017_36p1ifb_25nsTOPQ1_eLHM.root";
  TFile *inputBkg=TFile::Open(fBkg);
  TTree *ttW_np0=(TTree*)inputBkg->Get("nominal_Loose");

  std::cout<<"File operation done"<<std::endl;

  //Global event weights per tree
  Double_t signalWeight=1.0;
  Double_t ttW_np0Weight=1.0;

  factory->AddSignalTree(signal,signalWeight);
  factory->SetSignalWeightExpression("evtWeight");

  factory->AddBackgroundTree(ttW_np0,ttW_np0Weight);
  factory->SetBackgroundWeightExpression("evtWeight");

  //Apply additional cuts on the signal and background samples
  TCut mycut="";
  factory->PrepareTrainingAndTestTree(mycut,"SplitMode=random:!V:NormMode=None");

  // --- Book MVA method
  //
  //Boosted Decision Tree
  TString Option="!H:!V:NTrees=850:MinNodeSize=2.5%:MaxDepth=3:BoostType=AdaBoost:AdaBoostBeta=0.5:UseBaggedBoost:BaggedSampleFraction=0.5:SeparationType=GiniIndex:nCuts=20";

  //Book training method
  factory->BookMethod( TMVA::Types::kBDT, "BDT",
		       Option);

  //Train and evaluate
  factory->TrainAllMethods();
  factory->TestAllMethods();
  factory->EvaluateAllMethods();

  outputFile->Close();

  std::cout << "==> Wrote root file: " << outputFile->GetName() << std::endl;
  std::cout << "==> TMVAClassification is done!" << std::endl;

  delete factory;

  //Launch the GUI for the root macros
  if (!gROOT->IsBatch())
    TMVA::TMVAGui(outputFileName);

  return 0;
}

int main()
{
  return bdt_vlq();
}
<commit_msg>fix type<commit_after>//This is a testing version of the BDT training code
//Author: Zhaoyuan "Maxwell" Cui
//Physics department, Unversity of Arizona

/*------------------------------------------------------*\
|This code is designed for Vector-like B pair production |
\*----------------------------------------------------- */

#include "iostream"
#include "fstream"

#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TSystem.h"
#include "TROOT.h"

#include "TMVA/Factory.h"
#include "TMVA/Tools.h"
#include "TMVA/TMVAGui.h"

int bdt_vlq()
{
  //Load the library
  TMVA::Tools::Instance();

  std::cout<<std::endl;
  std::cout<<"==>Start BDT"<<std::endl;

  TString outputFileName("BDT_VLQ_BB.root");
  TFile *outputFile=TFile::Open(outputFileName, "RECREATE");

  //Register TMVA Factory
  TMVA::Factory *factory=new TMVA::Factory("BDT_VLQ", outputFile,
					   "V:!Silent:Color:DrawProgressBar:AnalysisType=Classification");

  //Add variables that will be used for MVA training
  factory->AddVariable("mu",'F');
  factory->AddVariable("el_pt.[0]",'F');
  factory->AddVariable("mu_pt.[0]",'F');
  factory->AddVariable("jet_pt.[0]",'F');
  factory->AddVariable("met_met",'F');
  factory->AddVariable("met_phi",'F');
  factory->AddVariable("SSee_2016",'I');
  factory->AddVariable("SSem_2016",'I');
  factory->AddVariable("SSmm_2016",'I');
  factory->AddVariable("eee_2016",'I');
  factory->AddVariable("eem_2016",'I');
  factory->AddVariable("emm_2016",'I');
  factory->AddVariable("mmm_2016",'I');
  factory->AddVariable("lep_pt.[0]",'I');
  factory->AddVariable("ht",'F');
  factory->AddVariable("met_sumet",'F');
  factory->AddVariable("bjet",'I');

  //Read training data
  //
  // --- Signal
  TString fSig="../../dataPreparation/signal/normalized_BBS_M1000_302494_SSsig_deterre_Apr2017_36p1ifb_25nsTOPQ1_eLHM.root";
  TFile *inputBB=TFile::Open(fSig);
  TTree *signal=(TTree*)inputBB->Get("nominal_Loose");

  // --- Background
  TString fBkg="../../dataPreparation/background/normalized_ttW_np0_410066_SSbkg_deterre_Apr2017_36p1ifb_25nsTOPQ1_eLHM.root";
  TFile *inputBkg=TFile::Open(fBkg);
  TTree *ttW_np0=(TTree*)inputBkg->Get("nominal_Loose");

  std::cout<<"File operation done"<<std::endl;

  //Global event weights per tree
  Double_t signalWeight=1.0;
  Double_t ttW_np0Weight=1.0;

  factory->AddSignalTree(signal,signalWeight);
  factory->SetSignalWeightExpression("evtWeight");

  factory->AddBackgroundTree(ttW_np0,ttW_np0Weight);
  factory->SetBackgroundWeightExpression("evtWeight");

  //Apply additional cuts on the signal and background samples
  TCut mycut="";
  factory->PrepareTrainingAndTestTree(mycut,"SplitMode=random:!V:NormMode=None");

  // --- Book MVA method
  //
  //Boosted Decision Tree
  TString Option="!H:!V:NTrees=850:MinNodeSize=2.5%:MaxDepth=3:BoostType=AdaBoost:AdaBoostBeta=0.5:UseBaggedBoost:BaggedSampleFraction=0.5:SeparationType=GiniIndex:nCuts=20";

  //Book training method
  factory->BookMethod( TMVA::Types::kBDT, "BDT",
		       Option);

  //Train and evaluate
  factory->TrainAllMethods();
  factory->TestAllMethods();
  factory->EvaluateAllMethods();

  outputFile->Close();

  std::cout << "==> Wrote root file: " << outputFile->GetName() << std::endl;
  std::cout << "==> TMVAClassification is done!" << std::endl;

  delete factory;

  //Launch the GUI for the root macros
  if (!gROOT->IsBatch())
    TMVA::TMVAGui(outputFileName);

  return 0;
}

int main()
{
  return bdt_vlq();
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2020 mogemimi. Distributed under the MIT license.

#pragma once

#include "Pomdog/Basic/Export.hpp"

namespace Pomdog {

/// Core application class that describes game logic and rendering.
///
/// Instances of this class are unique.
class POMDOG_EXPORT Game {
public:
    /// Constructs empty Game.
    Game() = default;

    Game(const Game&) = delete;
    Game& operator=(const Game&) = delete;
    virtual ~Game() = default;

    /// Initialization phase of the game.
    ///
    /// Called by GameHost once before any Update() or Draw().
    virtual void Initialize() = 0;

    /// Logic update phase of the game.
    ///
    /// Called by GameHost every frame before Update().
    ///
    /// Logic updates are frame-independent. More specifically, they are guarnteed
    /// to be called once in a *presentation interval*, which is set in a Bootstrap.
    /// @see X11::Bootstrap::SetPresentationInterval,
    ///      Win32::Bootstrap::SetPresentationInterval
    /// @note In Cocoa, *presentation interval* is always 60
    virtual void Update() = 0;

    /// Rendering phase of the game.
    ///
    /// Called by GameHost after every Update().
    ///
    /// @note Do all computations in Update()
    virtual void Draw() = 0;
};

} // namespace Pomdog
<commit_msg>Return explicit error value when initializing game<commit_after>// Copyright (c) 2013-2020 mogemimi. Distributed under the MIT license.

#pragma once

#include "Pomdog/Basic/Export.hpp"
#include <memory>

namespace Pomdog {
class Error;
} // namespace Pomdog

namespace Pomdog {

/// Core application class that describes game logic and rendering.
///
/// Instances of this class are unique.
class POMDOG_EXPORT Game {
public:
    /// Constructs empty Game.
    Game() = default;

    Game(const Game&) = delete;
    Game& operator=(const Game&) = delete;
    virtual ~Game() = default;

    /// Initialization phase of the game.
    ///
    /// Called by GameHost once before any Update() or Draw().
    [[nodiscard]] virtual std::shared_ptr<Error> Initialize() = 0;

    /// Logic update phase of the game.
    ///
    /// Called by GameHost every frame before Update().
    ///
    /// Logic updates are frame-independent. More specifically, they are guarnteed
    /// to be called once in a *presentation interval*, which is set in a Bootstrap.
    /// @see X11::Bootstrap::SetPresentationInterval,
    ///      Win32::Bootstrap::SetPresentationInterval
    /// @note In Cocoa, *presentation interval* is always 60
    virtual void Update() = 0;

    /// Rendering phase of the game.
    ///
    /// Called by GameHost after every Update().
    ///
    /// @note Do all computations in Update()
    virtual void Draw() = 0;
};

} // namespace Pomdog
<|endoftext|>


<commit_before>#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"
#include "guiutil.h"
#include "bitcoinunits.h"
#include "addressbookpage.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"

#include <QApplication>
#include <QClipboard>

SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
    QFrame(parent),
    ui(new Ui::SendCoinsEntry),
    model(0)
{
    ui->setupUi(this);

#ifdef Q_WS_MAC
    ui->payToLayout->setSpacing(4);
#endif

#if QT_VERSION >= 0x040700
    ui->payTo->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
#endif
    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(ui->payTo);

    GUIUtil::setupAddressWidget(ui->payTo, this);
}

SendCoinsEntry::~SendCoinsEntry()
{
    delete ui;
}

void SendCoinsEntry::on_pasteButton_clicked()
{
    // Paste text from clipboard into recipient field
    ui->payTo->setText(QApplication::clipboard()->text());
}

void SendCoinsEntry::on_addressBookButton_clicked()
{
    if(!model)
        return;
    AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
    dlg.setModel(model->getAddressTableModel());
    if(dlg.exec())
    {
        ui->payTo->setText(dlg.getReturnValue());
        ui->payAmount->setFocus();
    }
}

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    if(!model)
        return;
    ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));
}

void SendCoinsEntry::setModel(WalletModel *model)
{
    this->model = model;
}

void SendCoinsEntry::setRemoveEnabled(bool enabled)
{
    ui->deleteButton->setEnabled(enabled);
}

void SendCoinsEntry::clear()
{
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->payTo->setFocus();
    if(model && model->getOptionsModel())
    {
        ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}

void SendCoinsEntry::on_deleteButton_clicked()
{
    emit removeEntry(this);
}

bool SendCoinsEntry::validate()
{
    // Check input validity
    bool retval = true;

    if(!ui->payAmount->validate())
    {
        retval = false;
    }
    else
    {
        if(ui->payAmount->value() <= 0)
        {
            // Cannot send 0 coins or less
            ui->payAmount->setValid(false);
            retval = false;
        }
    }

    if(!ui->payTo->hasAcceptableInput() ||
       (model && !model->validateAddress(ui->payTo->text())))
    {
        ui->payTo->setValid(false);
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    SendCoinsRecipient rv;

    rv.address = ui->payTo->text();
    rv.label = ui->addAsLabel->text();
    rv.amount = ui->payAmount->value();

    return rv;
}

QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, ui->payTo);
    QWidget::setTabOrder(ui->payTo, ui->addressBookButton);
    QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
    QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
    QWidget::setTabOrder(ui->deleteButton, ui->addAsLabel);
    return ui->payAmount->setupTabChain(ui->addAsLabel);
}

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    ui->payTo->setText(value.address);
    ui->addAsLabel->setText(value.label);
    ui->payAmount->setValue(value.amount);
}

bool SendCoinsEntry::isClear()
{
    return ui->payTo->text().isEmpty();
}

void SendCoinsEntry::setFocus()
{
    ui->payTo->setFocus();
}

<commit_msg>Only fill in label from address book, if no label is filled in yet, fixes #840<commit_after>#include "sendcoinsentry.h"
#include "ui_sendcoinsentry.h"
#include "guiutil.h"
#include "bitcoinunits.h"
#include "addressbookpage.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"

#include <QApplication>
#include <QClipboard>

SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
    QFrame(parent),
    ui(new Ui::SendCoinsEntry),
    model(0)
{
    ui->setupUi(this);

#ifdef Q_WS_MAC
    ui->payToLayout->setSpacing(4);
#endif

#if QT_VERSION >= 0x040700
    ui->payTo->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
    ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
#endif
    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(ui->payTo);

    GUIUtil::setupAddressWidget(ui->payTo, this);
}

SendCoinsEntry::~SendCoinsEntry()
{
    delete ui;
}

void SendCoinsEntry::on_pasteButton_clicked()
{
    // Paste text from clipboard into recipient field
    ui->payTo->setText(QApplication::clipboard()->text());
}

void SendCoinsEntry::on_addressBookButton_clicked()
{
    if(!model)
        return;
    AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
    dlg.setModel(model->getAddressTableModel());
    if(dlg.exec())
    {
        ui->payTo->setText(dlg.getReturnValue());
        ui->payAmount->setFocus();
    }
}

void SendCoinsEntry::on_payTo_textChanged(const QString &address)
{
    if(!model)
        return;
    // Fill in label from address book, if no label is filled in yet
    if(ui->addAsLabel->text().isEmpty())
        ui->addAsLabel->setText(model->getAddressTableModel()->labelForAddress(address));}

void SendCoinsEntry::setModel(WalletModel *model)
{
    this->model = model;
}

void SendCoinsEntry::setRemoveEnabled(bool enabled)
{
    ui->deleteButton->setEnabled(enabled);
}

void SendCoinsEntry::clear()
{
    ui->payTo->clear();
    ui->addAsLabel->clear();
    ui->payAmount->clear();
    ui->payTo->setFocus();
    if(model && model->getOptionsModel())
    {
        ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
    }
}

void SendCoinsEntry::on_deleteButton_clicked()
{
    emit removeEntry(this);
}

bool SendCoinsEntry::validate()
{
    // Check input validity
    bool retval = true;

    if(!ui->payAmount->validate())
    {
        retval = false;
    }
    else
    {
        if(ui->payAmount->value() <= 0)
        {
            // Cannot send 0 coins or less
            ui->payAmount->setValid(false);
            retval = false;
        }
    }

    if(!ui->payTo->hasAcceptableInput() ||
       (model && !model->validateAddress(ui->payTo->text())))
    {
        ui->payTo->setValid(false);
        retval = false;
    }

    return retval;
}

SendCoinsRecipient SendCoinsEntry::getValue()
{
    SendCoinsRecipient rv;

    rv.address = ui->payTo->text();
    rv.label = ui->addAsLabel->text();
    rv.amount = ui->payAmount->value();

    return rv;
}

QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, ui->payTo);
    QWidget::setTabOrder(ui->payTo, ui->addressBookButton);
    QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
    QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
    QWidget::setTabOrder(ui->deleteButton, ui->addAsLabel);
    return ui->payAmount->setupTabChain(ui->addAsLabel);
}

void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
    ui->payTo->setText(value.address);
    ui->addAsLabel->setText(value.label);
    ui->payAmount->setValue(value.amount);
}

bool SendCoinsEntry::isClear()
{
    return ui->payTo->text().isEmpty();
}

void SendCoinsEntry::setFocus()
{
    ui->payTo->setFocus();
}

<|endoftext|>


<commit_before><commit_msg>rcx: fix unused return warnings on more system calls<commit_after><|endoftext|>


<commit_before><commit_msg>coverity#708183 Uninitialized scalar field<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2017 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Teapotnet.                                     *
 *                                                                       *
 *   Teapotnet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Teapotnet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Teapotnet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "tpn/board.hpp"
#include "tpn/resource.hpp"
#include "tpn/cache.hpp"
#include "tpn/html.hpp"
#include "tpn/user.hpp"
#include "tpn/store.hpp"
#include "tpn/config.hpp"

#include "pla/jsonserializer.hpp"
#include "pla/binaryserializer.hpp"
#include "pla/object.hpp"

namespace tpn
{

Board::Board(const String &name, const String &secret, const String &displayName) :
	mName(name),
	mDisplayName(displayName),
	mSecret(secret),
	mHasNew(false),
	mUnread(0)
{
	if(!mName.empty() && mName[0] == '/') mName = mName.substr(1);
	Assert(!mName.empty());

	Interface::Instance->add(urlPrefix(), this);

	const String prefix = "/mail/" + mName;

	Set<BinaryString> digests;
	Store::Instance->retrieveValue(Store::Hash(prefix), digests);

	for(auto it = digests.begin(); it != digests.end(); ++it)
	{
		//LogDebug("Board", "Retrieved digest: " + it->toString());
		if(fetch(Network::Link::Null, prefix, "/", *it, false))
			incoming(Network::Link::Null, prefix, "/", *it);
	}

	publish(prefix);
	subscribe(prefix);
}

Board::~Board(void)
{
	for(auto board : mSubBoards)
	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoards.erase(this);
	}

	Interface::Instance->remove(urlPrefix(), this);

	const String prefix = "/mail/" + mName;
	unpublish(prefix);
	unsubscribe(prefix);
}

String Board::urlPrefix(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	return "/mail/" + mName;
}

bool Board::hasNew(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	bool value = false;
	std::swap(mHasNew, value);
	return value;
}

int Board::unread(void) const
{
	// TODO: count unread
	return 0;
}

BinaryString Board::digest(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	return mDigest;
}

void Board::addSubBoard(sptr<Board> board)
{
	{
		std::unique_lock<std::mutex> lock(mMutex);
		mSubBoards.insert(board);
	}

	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoard.insert(this);
	}
}

void Board::removeSubBoard(sptr<Board> board)
{
	{
		std::unique_lock<std::mutex> lock(mMutex);
		mSubBoards.erase(board);
	}

	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoard.erase(this);
	}
}

bool Board::post(const List<Mail> &mails)
{
	const String prefix = "/mail/" + mName;

	// Issue mails
	for(const Mail &m : mails)
		issue(prefix, m);

	// Add to chain
	return add(mails);
}

bool Board::post(const Mail &mail)
{
	List<Mail> tmp;
	tmp.push_back(mail);
	return post(tmp);
}

bool Board::add(const List<Mail> &mails)
{
	// First, append to list
	appendMails(mails);

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		// Write messages to temporary file
		String tempFileName = File::TempName();
		File tempFile(tempFileName, File::Truncate);
		BinarySerializer serializer(&tempFile);
		for(const Mail &m : mails)
			serializer << m;
		tempFile.close();

		// Move to cache
		Resource resource;
		Resource::Specs specs;
		specs.name = mName;
		specs.type = "mail";
		specs.secret = mSecret;
		specs.previous = mDigests;	// chain other messages
		resource.cache(tempFileName, specs);

		// Retrieve digest and store it
		const String prefix = "/mail/" + mName;
		BinaryString digest = resource.digest();
		Store::Instance->storeValue(Store::Hash(prefix), digest, Store::Permanent);

		// Update digests
		mPreviousDigests.insertAll(mDigests);
		mDigests.clear();
		mDigests.insert(digest);
		mProcessedDigests.insert(digest);

		// Republish prefix
		const String prefix = "/mail/" + mName;
		publish(prefix);
		return true;
	}
	catch(const Exception &e)
	{
		LogWarn("Board::process", String("Board post failed: ") + e.what());
		return false;
	}
}

void Board::appendMails(const List<Mail> &mails)
{
	for(const Mail &m : mails)
		mMails.emplace_back(std::move(m));

	// Notify HTTP clients
	mCondition.notify_all();
}

bool Board::anounce(const Network::Link &link, const String &prefix, const String &path, List<BinaryString> &targets)
{
	std::unique_lock<std::mutex> lock(mMutex);
	targets.clear();
	for(auto d : mDigests)
		targets.emplace_back(std::move(d));
	return !targets.empty();
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const BinaryString &target)
{
	{
		std::unique_lock<std::mutex> lock(mMutex);
		if(target == mDigest)
			return false;
	}

	if(!fetch(link, prefix, path, target, true))
		return false;

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		Resource resource(target, true);	// local only (already fetched)
		if(resource.type() != "mail")
			return false;

		if(!mPreviousDigests.contains(target))
			mDigests.insert(target);	// top-level

		// Fetch previous
		List<BinaryString> previous;
		if(resource.getPreviousDigests(previous))
			for(const BinaryString &d : previous)
			{
				mDigests.erase(d);
				mPreviousDigests.insert(d);
				fetch(link, prefix, path, d, true);
			}

		if(!mProcessedDigests.contains(target))
		{
			mProcessedDigests.insert(target);

			List<Mails> tmp;
			Resource::Reader reader(&resource, mSecret);
			BinarySerializer serializer(&reader);
			Mail m;
			while(!!(serializer >> m))
			{
				if(m.empty()) continue;
				tmp.emplace_back(std::move(m));
			}

			appendMails(tmp);
		}
	}
	catch(const Exception &e)
	{
		LogWarn("Board::incoming", e.what());
	}

	return true;
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const Mail &mail)
{
	List<Mail> tmp;
	tmp.push_back(mail);
	return add(tmp);
}

void Board::http(const String &prefix, Http::Request &request)
{
	Assert(!request.url.empty());

	try {
		if(request.url == "/")
		{
			if(request.method == "POST")
			{
				if(request.post.contains("message") && !request.post["message"].empty())
				{
					Mail mail;
					mail.setContent(request.post["message"]);

					if(request.post.contains("parent"))
					{
						BinaryString parent;
						request.post["parent"].extract(parent);
						mail.setParent(parent);
					}

					if(request.post.contains("attachment"))
					{
						BinaryString attachment;
						request.post["attachment"].extract(attachment);
						if(!attachment.empty())
							mail.addAttachment(attachment);
					}

					if(request.post.contains("author"))
					{
						mail.setAuthor(request.post["author"]);
					}
					else {
						sptr<User> user = getAuthenticatedUser(request);
						if(user) {
							mail.setAuthor(user->name());
							mail.sign(user->identifier(), user->privateKey());
						}
					}

					post(mail);

					Http::Response response(request, 200);
					response.send();
				}

				throw 400;
			}

			if(request.get.contains("json"))
			{
				int next = 0;
				if(request.get.contains("next"))
					request.get["next"].extract(next);

				duration timeout = milliseconds(Config::Get("request_timeout").toInt());
				if(request.get.contains("timeout"))
					timeout = seconds(request.get["timeout"].toDouble());

				decltype(mUnorderedMails) temp;
				{
					std::unique_lock<std::mutex> lock(mMutex);

					if(next >= int(mUnorderedMails.size()))
					{
						mCondition.wait_for(lock, std::chrono::duration<double>(timeout), [this, next]() {
							return next < int(mUnorderedMails.size());
						});
					}

					temp.reserve(int(mUnorderedMails.size() - next));
					for(int i = next; i < int(mUnorderedMails.size()); ++i)
						temp.push_back(mUnorderedMails[i]);

					mUnread = 0;
					mHasNew = false;
				}

				Http::Response response(request, 200);
				response.headers["Content-Type"] = "application/json";
				response.send();

				JsonSerializer json(response.stream);
				json.setOptionalOutputMode(true);
				json << temp;
				return;
			}

			bool isPopup = request.get.contains("popup");
			bool isFrame = request.get.contains("frame");

			Http::Response response(request, 200);
			response.send();

			Html page(response.stream);

			String title;
			{
				std::unique_lock<std::mutex> lock(mMutex);
				title = (!mDisplayName.empty() ? mDisplayName : "Board " + mName);
			}

			page.header(title, isPopup || isFrame);

			if(!isFrame)
			{
				page.open("div","topmenu");
				if(isPopup) page.span(title, ".button");

// TODO: should be hidden in CSS
#ifndef ANDROID
				if(!isPopup)
				{
					String popupUrl = Http::AppendParam(request.fullUrl, "popup");
					page.raw("Popup");
				}
#endif

				page.close("div");
			}

			page.open("div", ".replypanel");

			sptr<User> user = getAuthenticatedUser(request);
			if(user)
			{
				page.javascript("var TokenMail = '"+user->generateToken("mail")+"';\n\
						var TokenDirectory = '"+user->generateToken("directory")+"';\n\
						var TokenContact = '"+user->generateToken("contact")+"';\n\
						var UrlSelector = '"+user->urlPrefix()+"/myself/files/?json';\n\
						var UrlUpload = '"+user->urlPrefix()+"/files/_upload/?json';");

				page.raw("");
			}

			page.openForm("#", "post", "boardform");
			page.textarea("input");
			page.input("hidden", "attachment");
			page.input("hidden", "attachmentname");
			page.closeForm();
			page.close("div");
			page.div("","#attachedfile.attachedfile");
			page.div("", "#fileSelector.fileselector");

			if(isPopup) page.open("div", "board");
			else page.open("div", "board.box");

			page.open("div", "mail");
			page.open("p"); page.text("No messages"); page.close("p");
			page.close("div");

			page.close("div");

			page.javascript("function post() {\n\
					var message = $(document.boardform.input).val();\n\
					var attachment = $(document.boardform.attachment).val();\n\
					if(!message) return false;\n\
					var fields = {};\n\
					fields['message'] = message;\n\
					if(attachment) fields['attachment'] = attachment;\n\
					$.post('"+prefix+request.url+"', fields)\n\
						.fail(function(jqXHR, textStatus) {\n\
							alert('The message could not be sent.');\n\
						});\n\
					$(document.boardform.input).val('');\n\
					$(document.boardform.attachment).val('');\n\
					$(document.boardform.attachmentname).val('');\n\
					$('#attachedfile').hide();\n\
				}\n\
				$(document.boardform).submit(function() {\n\
					post();\n\
					return false;\n\
				});\n\
				$(document.boardform.attachment).change(function() {\n\
					$('#attachedfile').html('');\n\
					$('#attachedfile').hide();\n\
					var filename = $(document.boardform.attachmentname).val();\n\
					if(filename != '') {\n\
						$('#attachedfile').append('');\n\
						$('#attachedfile').append(''+filename+'');\n\
						$('#attachedfile').show();\n\
					}\n\
					$(document.boardform.input).focus();\n\
					if($(document.boardform.input).val() == '') {\n\
						$(document.boardform.input).val(filename);\n\
						$(document.boardform.input).select();\n\
					}\n\
				});\n\
				$('#attachedfile').hide();");

			unsigned refreshPeriod = 2000;
			page.javascript("setMailReceiver('"+Http::AppendParam(request.fullUrl, "json")+"','#mail', "+String::number(refreshPeriod)+");");

			page.footer();
			return;
		}
	}
	catch(const Exception &e)
	{
		LogWarn("AddressBook::http", e.what());
		throw 500;
	}

	throw 404;
}

}
<commit_msg>Added TODO<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2017 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Teapotnet.                                     *
 *                                                                       *
 *   Teapotnet is free software: you can redistribute it and/or modify   *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Teapotnet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Teapotnet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "tpn/board.hpp"
#include "tpn/resource.hpp"
#include "tpn/cache.hpp"
#include "tpn/html.hpp"
#include "tpn/user.hpp"
#include "tpn/store.hpp"
#include "tpn/config.hpp"

#include "pla/jsonserializer.hpp"
#include "pla/binaryserializer.hpp"
#include "pla/object.hpp"

namespace tpn
{

Board::Board(const String &name, const String &secret, const String &displayName) :
	mName(name),
	mDisplayName(displayName),
	mSecret(secret),
	mHasNew(false),
	mUnread(0)
{
	if(!mName.empty() && mName[0] == '/') mName = mName.substr(1);
	Assert(!mName.empty());

	Interface::Instance->add(urlPrefix(), this);

	const String prefix = "/mail/" + mName;

	Set<BinaryString> digests;
	Store::Instance->retrieveValue(Store::Hash(prefix), digests);

	for(auto it = digests.begin(); it != digests.end(); ++it)
	{
		//LogDebug("Board", "Retrieved digest: " + it->toString());
		if(fetch(Network::Link::Null, prefix, "/", *it, false))
			incoming(Network::Link::Null, prefix, "/", *it);
	}

	publish(prefix);
	subscribe(prefix);
}

Board::~Board(void)
{
	for(auto board : mSubBoards)
	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoards.erase(this);
	}

	Interface::Instance->remove(urlPrefix(), this);

	const String prefix = "/mail/" + mName;
	unpublish(prefix);
	unsubscribe(prefix);
}

String Board::urlPrefix(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	return "/mail/" + mName;
}

bool Board::hasNew(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	bool value = false;
	std::swap(mHasNew, value);
	return value;
}

int Board::unread(void) const
{
	// TODO: count unread
	return 0;
}

BinaryString Board::digest(void) const
{
	std::unique_lock<std::mutex> lock(mMutex);
	return mDigest;
}

void Board::addSubBoard(sptr<Board> board)
{
	{
		std::unique_lock<std::mutex> lock(mMutex);
		mSubBoards.insert(board);
	}

	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoard.insert(this);
	}
}

void Board::removeSubBoard(sptr<Board> board)
{
	{
		std::unique_lock<std::mutex> lock(mMutex);
		mSubBoards.erase(board);
	}

	{
		std::unique_lock<std::mutex> lock(board->mMutex);
		board->mBoard.erase(this);
	}
}

bool Board::post(const List<Mail> &mails)
{
	const String prefix = "/mail/" + mName;

	// Issue mails
	for(const Mail &m : mails)
		issue(prefix, m);

	// Add to chain
	return add(mails);
}

bool Board::post(const Mail &mail)
{
	List<Mail> tmp;
	tmp.push_back(mail);
	return post(tmp);
}

bool Board::add(const List<Mail> &mails)
{
	// First, append to list
	appendMails(mails);

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		// Write messages to temporary file
		String tempFileName = File::TempName();
		File tempFile(tempFileName, File::Truncate);
		BinarySerializer serializer(&tempFile);
		for(const Mail &m : mails)
			serializer << m;
		tempFile.close();

		// Move to cache
		Resource resource;
		Resource::Specs specs;
		specs.name = mName;
		specs.type = "mail";
		specs.secret = mSecret;
		specs.previous = mDigests;	// chain other messages
		resource.cache(tempFileName, specs);

		// Retrieve digest and store it
		const String prefix = "/mail/" + mName;
		BinaryString digest = resource.digest();
		Store::Instance->storeValue(Store::Hash(prefix), digest, Store::Permanent);

		// Update digests
		mPreviousDigests.insertAll(mDigests);
		mDigests.clear();
		mDigests.insert(digest);
		mProcessedDigests.insert(digest);

		// Republish prefix
		const String prefix = "/mail/" + mName;
		publish(prefix);
		return true;
	}
	catch(const Exception &e)
	{
		LogWarn("Board::process", String("Board post failed: ") + e.what());
		return false;
	}
}

void Board::appendMails(const List<Mail> &mails)
{
	for(const Mail &m : mails)
		mMails.emplace_back(std::move(m));

	// Notify HTTP clients
	mCondition.notify_all();

	// TODO: mBoards
}

bool Board::anounce(const Network::Link &link, const String &prefix, const String &path, List<BinaryString> &targets)
{
	std::unique_lock<std::mutex> lock(mMutex);
	targets.clear();
	for(auto d : mDigests)
		targets.emplace_back(std::move(d));
	return !targets.empty();
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const BinaryString &target)
{
	{
		std::unique_lock<std::mutex> lock(mMutex);
		if(target == mDigest)
			return false;
	}

	if(!fetch(link, prefix, path, target, true))
		return false;

	try {
		std::unique_lock<std::mutex> lock(mMutex);

		Resource resource(target, true);	// local only (already fetched)
		if(resource.type() != "mail")
			return false;

		if(!mPreviousDigests.contains(target))
			mDigests.insert(target);	// top-level

		// Fetch previous
		List<BinaryString> previous;
		if(resource.getPreviousDigests(previous))
			for(const BinaryString &d : previous)
			{
				mDigests.erase(d);
				mPreviousDigests.insert(d);
				fetch(link, prefix, path, d, true);
			}

		if(!mProcessedDigests.contains(target))
		{
			mProcessedDigests.insert(target);

			List<Mails> tmp;
			Resource::Reader reader(&resource, mSecret);
			BinarySerializer serializer(&reader);
			Mail m;
			while(!!(serializer >> m))
			{
				if(m.empty()) continue;
				tmp.emplace_back(std::move(m));
			}

			appendMails(tmp);
		}
	}
	catch(const Exception &e)
	{
		LogWarn("Board::incoming", e.what());
	}

	return true;
}

bool Board::incoming(const Network::Link &link, const String &prefix, const String &path, const Mail &mail)
{
	List<Mail> tmp;
	tmp.push_back(mail);
	return add(tmp);
}

void Board::http(const String &prefix, Http::Request &request)
{
	Assert(!request.url.empty());

	try {
		if(request.url == "/")
		{
			if(request.method == "POST")
			{
				if(request.post.contains("message") && !request.post["message"].empty())
				{
					Mail mail;
					mail.setContent(request.post["message"]);

					if(request.post.contains("parent"))
					{
						BinaryString parent;
						request.post["parent"].extract(parent);
						mail.setParent(parent);
					}

					if(request.post.contains("attachment"))
					{
						BinaryString attachment;
						request.post["attachment"].extract(attachment);
						if(!attachment.empty())
							mail.addAttachment(attachment);
					}

					if(request.post.contains("author"))
					{
						mail.setAuthor(request.post["author"]);
					}
					else {
						sptr<User> user = getAuthenticatedUser(request);
						if(user) {
							mail.setAuthor(user->name());
							mail.sign(user->identifier(), user->privateKey());
						}
					}

					post(mail);

					Http::Response response(request, 200);
					response.send();
				}

				throw 400;
			}

			if(request.get.contains("json"))
			{
				int next = 0;
				if(request.get.contains("next"))
					request.get["next"].extract(next);

				duration timeout = milliseconds(Config::Get("request_timeout").toInt());
				if(request.get.contains("timeout"))
					timeout = seconds(request.get["timeout"].toDouble());

				decltype(mUnorderedMails) temp;
				{
					std::unique_lock<std::mutex> lock(mMutex);

					if(next >= int(mUnorderedMails.size()))
					{
						mCondition.wait_for(lock, std::chrono::duration<double>(timeout), [this, next]() {
							return next < int(mUnorderedMails.size());
						});
					}

					temp.reserve(int(mUnorderedMails.size() - next));
					for(int i = next; i < int(mUnorderedMails.size()); ++i)
						temp.push_back(mUnorderedMails[i]);

					mUnread = 0;
					mHasNew = false;
				}

				Http::Response response(request, 200);
				response.headers["Content-Type"] = "application/json";
				response.send();

				JsonSerializer json(response.stream);
				json.setOptionalOutputMode(true);
				json << temp;
				return;
			}

			bool isPopup = request.get.contains("popup");
			bool isFrame = request.get.contains("frame");

			Http::Response response(request, 200);
			response.send();

			Html page(response.stream);

			String title;
			{
				std::unique_lock<std::mutex> lock(mMutex);
				title = (!mDisplayName.empty() ? mDisplayName : "Board " + mName);
			}

			page.header(title, isPopup || isFrame);

			if(!isFrame)
			{
				page.open("div","topmenu");
				if(isPopup) page.span(title, ".button");

// TODO: should be hidden in CSS
#ifndef ANDROID
				if(!isPopup)
				{
					String popupUrl = Http::AppendParam(request.fullUrl, "popup");
					page.raw("Popup");
				}
#endif

				page.close("div");
			}

			page.open("div", ".replypanel");

			sptr<User> user = getAuthenticatedUser(request);
			if(user)
			{
				page.javascript("var TokenMail = '"+user->generateToken("mail")+"';\n\
						var TokenDirectory = '"+user->generateToken("directory")+"';\n\
						var TokenContact = '"+user->generateToken("contact")+"';\n\
						var UrlSelector = '"+user->urlPrefix()+"/myself/files/?json';\n\
						var UrlUpload = '"+user->urlPrefix()+"/files/_upload/?json';");

				page.raw("");
			}

			page.openForm("#", "post", "boardform");
			page.textarea("input");
			page.input("hidden", "attachment");
			page.input("hidden", "attachmentname");
			page.closeForm();
			page.close("div");
			page.div("","#attachedfile.attachedfile");
			page.div("", "#fileSelector.fileselector");

			if(isPopup) page.open("div", "board");
			else page.open("div", "board.box");

			page.open("div", "mail");
			page.open("p"); page.text("No messages"); page.close("p");
			page.close("div");

			page.close("div");

			page.javascript("function post() {\n\
					var message = $(document.boardform.input).val();\n\
					var attachment = $(document.boardform.attachment).val();\n\
					if(!message) return false;\n\
					var fields = {};\n\
					fields['message'] = message;\n\
					if(attachment) fields['attachment'] = attachment;\n\
					$.post('"+prefix+request.url+"', fields)\n\
						.fail(function(jqXHR, textStatus) {\n\
							alert('The message could not be sent.');\n\
						});\n\
					$(document.boardform.input).val('');\n\
					$(document.boardform.attachment).val('');\n\
					$(document.boardform.attachmentname).val('');\n\
					$('#attachedfile').hide();\n\
				}\n\
				$(document.boardform).submit(function() {\n\
					post();\n\
					return false;\n\
				});\n\
				$(document.boardform.attachment).change(function() {\n\
					$('#attachedfile').html('');\n\
					$('#attachedfile').hide();\n\
					var filename = $(document.boardform.attachmentname).val();\n\
					if(filename != '') {\n\
						$('#attachedfile').append('');\n\
						$('#attachedfile').append(''+filename+'');\n\
						$('#attachedfile').show();\n\
					}\n\
					$(document.boardform.input).focus();\n\
					if($(document.boardform.input).val() == '') {\n\
						$(document.boardform.input).val(filename);\n\
						$(document.boardform.input).select();\n\
					}\n\
				});\n\
				$('#attachedfile').hide();");

			unsigned refreshPeriod = 2000;
			page.javascript("setMailReceiver('"+Http::AppendParam(request.fullUrl, "json")+"','#mail', "+String::number(refreshPeriod)+");");

			page.footer();
			return;
		}
	}
	catch(const Exception &e)
	{
		LogWarn("AddressBook::http", e.what());
		throw 500;
	}

	throw 404;
}

}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 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
 *
 *****************************************************************************/

#ifndef MAPNIK_SYMBOLIZER_UTILS_HPP
#define MAPNIK_SYMBOLIZER_UTILS_HPP

// mapnik
#include <mapnik/symbolizer_keys.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/path_expression.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/color.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/transform_processor.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/xml_tree.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/evaluate_global_attributes.hpp>
#include <mapnik/parse_transform.hpp>
#include <mapnik/util/dasharray_parser.hpp>
#include <mapnik/util/variant.hpp>

namespace mapnik {

template <typename Symbolizer>
struct symbolizer_traits
{
    static char const* name() { return "Unknown";}
};

template<>
struct symbolizer_traits<point_symbolizer>
{
    static char const* name() { return "PointSymbolizer";}
};

template<>
struct symbolizer_traits<line_symbolizer>
{
    static char const* name() { return "LineSymbolizer";}
};

template<>
struct symbolizer_traits<polygon_symbolizer>
{
    static char const* name() { return "PolygonSymbolizer";}
};

template<>
struct symbolizer_traits<text_symbolizer>
{
    static char const* name() { return "TextSymbolizer";}
};

template<>
struct symbolizer_traits<line_pattern_symbolizer>
{
    static char const* name() { return "LinePatternSymbolizer";}
};

template<>
struct symbolizer_traits<polygon_pattern_symbolizer>
{
    static char const* name() { return "PolygonPatternSymbolizer";}
};

template<>
struct symbolizer_traits<markers_symbolizer>
{
    static char const* name() { return "MarkersSymbolizer";}
};

template<>
struct symbolizer_traits<shield_symbolizer>
{
    static char const* name() { return "ShieldSymbolizer";}
};

template<>
struct symbolizer_traits<raster_symbolizer>
{
    static char const* name() { return "RasterSymbolizer";}
};

template<>
struct symbolizer_traits<building_symbolizer>
{
    static char const* name() { return "BuildingSymbolizer";}
};

template<>
struct symbolizer_traits<debug_symbolizer>
{
    static char const* name() { return "DebugSymbolizer";}
};

template<>
struct symbolizer_traits<dot_symbolizer>
{
    static char const* name() { return "DotSymbolizer";}
};

template<>
struct symbolizer_traits<collision_symbolizer>
{
    static char const* name() { return "CollisionSymbolizer";}
};

// symbolizer name impl
namespace detail {

struct symbolizer_name_impl
{
public:
    template <typename Symbolizer>
    std::string operator () (Symbolizer const&) const
    {
        return symbolizer_traits<Symbolizer>::name();
    }
};
}

inline std::string symbolizer_name(symbolizer const& sym)
{
    std::string type = util::apply_visitor( detail::symbolizer_name_impl(), sym);
    return type;
}

// https://github.com/mapnik/mapnik/issues/2324
/*

template <typename Meta>
class symbolizer_property_value_string
{
public:
    symbolizer_property_value_string (Meta const& meta)
        : meta_(meta) {}

    std::string operator() ( mapnik::enumeration_wrapper const& e) const
    {
        std::stringstream ss;
        auto const& convert_fun_ptr(std::get<1>(meta_));
        if ( convert_fun_ptr )
        {
            ss << convert_fun_ptr(e);
        }
        return ss.str();
    }

    std::string operator () ( path_expression_ptr const& expr) const
    {
        std::ostringstream ss;
        if (expr)
        {
            ss << '\"' << path_processor::to_string(*expr) << '\"';
        }
        return ss.str();
    }

    std::string operator () (text_placements_ptr const& expr) const
    {
        return std::string("\"<fixme-text-placement-ptr>\"");
    }

    std::string operator () (raster_colorizer_ptr const& expr) const
    {
        return std::string("\"<fixme-raster-colorizer-ptr>\"");
    }

    std::string operator () (transform_type const& expr) const
    {
        std::ostringstream ss;
        if (expr)
        {
            ss << '\"' << transform_processor_type::to_string(*expr) << '\"';
        }
        return ss.str();
    }

    std::string operator () (expression_ptr const& expr) const
    {
        std::ostringstream ss;
        if (expr)
        {
            ss << '\"' << "FIXME" <<  '\"';
        }
        return ss.str();
    }

    std::string operator () (color const& c) const
    {
        std::ostringstream ss;
        ss << '\"' << c << '\"';
        return ss.str();
    }

    std::string operator () (dash_array const& dash) const
    {
        std::ostringstream ss;
        for (std::size_t i = 0; i < dash.size(); ++i)
        {
            ss << dash[i].first << ", " << dash[i].second;
            if ( i + 1 < dash.size() ) ss << ',';
        }
        return ss.str();
    }

    template <typename T>
    std::string operator () ( T const& val ) const
    {
        std::ostringstream ss;
        ss << val;
        return ss.str();
    }

private:
    Meta const& meta_;
};

struct symbolizer_to_json
{
    using result_type = std::string;

    template <typename T>
    auto operator() (T const& sym) const -> result_type
    {
        std::stringstream ss;
        ss << "{\"type\":\"" << mapnik::symbolizer_traits<T>::name() << "\",";
        ss << "\"properties\":{";
        bool first = true;
        for (auto const& prop : sym.properties)
        {
            auto const& meta = mapnik::get_meta(prop.first);
            if (first) first = false;
            else ss << ",";
            ss << "\"" <<  std::get<0>(meta) << "\":";
            ss << util::apply_visitor(symbolizer_property_value_string<property_meta_type>(meta),prop.second);
        }
        ss << "}}";
        return ss.str();
    }
};

*/

namespace {

template <typename Symbolizer, typename T>
struct set_property_impl
{
    static void apply(Symbolizer &, mapnik::keys, std::string const&)
    {
        std::cerr << "do nothing" << std::endl;
    }
};

template <typename Symbolizer>
struct set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_color> >
{
    static void apply(Symbolizer & sym, mapnik::keys key, std::string const& val)
    {
        if (boost::optional<color> c = mapnik::parse_color(val))
        {
            put(sym, key, *c);
        }
        else
        {
            throw config_error("Failed to parse color: \"" + val + "\"");
        }
    }
};

template <typename Symbolizer>
struct set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_double> >
{
    static void apply(Symbolizer &, mapnik::keys, std::string const&)
    {
        std::cerr << " expects double" << std::endl;
    }
};

template <typename Symbolizer>
struct set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_bool> >
{
    static void apply(Symbolizer &, mapnik::keys, std::string const&)
    {
        std::cerr << " expects bool" << std::endl;
    }
};

}

template <typename Symbolizer, typename T>
inline void set_property(Symbolizer & sym, mapnik::keys key, T const& val)
{
    switch (std::get<2>(get_meta(key)))
    {
    case property_types::target_bool:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_bool> >::apply(sym,key,val);
        break;
    case property_types::target_integer:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_integer> >::apply(sym,key,val);
        break;
    case property_types::target_double:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_double> >::apply(sym,key,val);
        break;
    case property_types::target_color:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_color> >::apply(sym,key,val);
        break;
    default:
        break;
    }
}

template <typename Symbolizer, typename T>
inline void set_property_from_value(Symbolizer & sym, mapnik::keys key, T const& val)
{
    switch (std::get<2>(get_meta(key)))
    {
    case property_types::target_bool:
        put(sym, key, val.to_bool());
        break;
    case property_types::target_integer:
        put(sym, key, val.to_int());
        break;
    case property_types::target_double:
        put(sym, key, val.to_double());
        break;
    case property_types::target_color:
        if (boost::optional<color> c = mapnik::parse_color(val.to_string()))
        {
            put(sym, key, *c);
        }
        else
        {
            throw config_error("Failed to parse color: \"" + val.to_string() + "\"");
        }
        break;
    default:
        break;
    }
}

namespace detail {
// helpers
template <typename Symbolizer, typename T, bool is_enum = false>
struct set_symbolizer_property_impl
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const& node)
    {
        using value_type = T;
        bool error = false;
        if (boost::optional<value_type> val = node.get_opt_attr<value_type>(name, &error))
        {
            put(sym, key, *val);
            return true;
        }
        if (error)
        {
            // try parsing as an expression
            if (boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name, &error))
            {
                // first try pre-evaluate expressions which don't have dynamic properties
                auto result = pre_evaluate_expression<mapnik::value>(*val);
                if (std::get<1>(result))
                {
                    set_property_from_value(sym, key,std::get<0>(result));
                }
                else
                {
                    // expression_ptr
                    put(sym, key, *val);
                }
                return true;
            }
            return false;
        }
        return true;
    }
};

template <typename Symbolizer>
struct set_symbolizer_property_impl<Symbolizer,transform_type,false>
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
    {
        boost::optional<std::string> transform = node.get_opt_attr<std::string>(name);
        if (transform) put(sym, key, mapnik::parse_transform(*transform));
        return true;
    }
};

template <typename Symbolizer>
struct set_symbolizer_property_impl<Symbolizer,dash_array,false>
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
    {
        boost::optional<std::string> str = node.get_opt_attr<std::string>(name);
        if (str)
        {
            dash_array dash;
            if (util::parse_dasharray(*str,dash))
            {
                put(sym,key,dash);
            }
            else
            {
                boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
                if (val)
                {
                    // first try pre-evaluate expressions which don't have dynamic properties
                    auto result = pre_evaluate_expression<mapnik::value>(*val);
                    if (std::get<1>(result))
                    {
                        set_property_from_value(sym, key,std::get<0>(result));
                    }
                    else
                    {
                        // expression_ptr
                        put(sym, key, *val);
                    }
                }
                else
                {
                    MAPNIK_LOG_ERROR(set_symbolizer_property_impl) <<
                        std::string("Failed to parse dasharray ") + "'. Expected a " +
                        "list of floats or 'none' but got '" + (*str) + "'";
                    return false;
                }
            }
        }
        return true;
    }
};

template <typename Symbolizer, typename T>
struct set_symbolizer_property_impl<Symbolizer, T, true>
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
    {
        using value_type = T;
        boost::optional<std::string> enum_str = node.get_opt_attr<std::string>(name);
        if (enum_str)
        {
            boost::optional<value_type> enum_val = detail::enum_traits<value_type>::from_string(*enum_str);
            if (enum_val)
            {
                put(sym, key, *enum_val);
            }
            else
            {
                boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
                if (val)
                {
                    // first try pre-evaluating expression
                    auto result = pre_evaluate_expression<value>(*val);
                    if (std::get<1>(result))
                    {
                        boost::optional<value_type> enum_val2 = detail::enum_traits<value_type>::from_string(std::get<0>(result).to_string());
                        if (enum_val2)
                        {
                            put(sym, key, *enum_val);
                        }
                        else
                        {
                            // can't evaluate
                            return false;
                        }
                    }
                    else
                    {
                        // put expression_ptr
                        put(sym, key, *val);
                    }
                }
                else
                {
                    return false;
                }
            }
        }
        return true;
    }
};

} // namespace detail

template <typename Symbolizer, typename T>
void set_symbolizer_property(Symbolizer & sym, keys key, xml_node const& node)
{
    std::string const& name = std::get<0>(get_meta(key));
    if (node.has_attribute(name))
    {
        if (!detail::set_symbolizer_property_impl<Symbolizer,T, std::is_enum<T>::value>::apply(sym,key,name,node))
        {
            throw config_error("set_symbolizer_property '" + name + "'");
        }
    }
}

}

#endif // MAPNIK_SYMBOLIZER_UTILS_HPP
<commit_msg>This code is definitely dead<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 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
 *
 *****************************************************************************/

#ifndef MAPNIK_SYMBOLIZER_UTILS_HPP
#define MAPNIK_SYMBOLIZER_UTILS_HPP

// mapnik
#include <mapnik/symbolizer_keys.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/path_expression.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/color.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/transform_processor.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/xml_tree.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/evaluate_global_attributes.hpp>
#include <mapnik/parse_transform.hpp>
#include <mapnik/util/dasharray_parser.hpp>
#include <mapnik/util/variant.hpp>

namespace mapnik {

template <typename Symbolizer>
struct symbolizer_traits
{
    static char const* name() { return "Unknown";}
};

template<>
struct symbolizer_traits<point_symbolizer>
{
    static char const* name() { return "PointSymbolizer";}
};

template<>
struct symbolizer_traits<line_symbolizer>
{
    static char const* name() { return "LineSymbolizer";}
};

template<>
struct symbolizer_traits<polygon_symbolizer>
{
    static char const* name() { return "PolygonSymbolizer";}
};

template<>
struct symbolizer_traits<text_symbolizer>
{
    static char const* name() { return "TextSymbolizer";}
};

template<>
struct symbolizer_traits<line_pattern_symbolizer>
{
    static char const* name() { return "LinePatternSymbolizer";}
};

template<>
struct symbolizer_traits<polygon_pattern_symbolizer>
{
    static char const* name() { return "PolygonPatternSymbolizer";}
};

template<>
struct symbolizer_traits<markers_symbolizer>
{
    static char const* name() { return "MarkersSymbolizer";}
};

template<>
struct symbolizer_traits<shield_symbolizer>
{
    static char const* name() { return "ShieldSymbolizer";}
};

template<>
struct symbolizer_traits<raster_symbolizer>
{
    static char const* name() { return "RasterSymbolizer";}
};

template<>
struct symbolizer_traits<building_symbolizer>
{
    static char const* name() { return "BuildingSymbolizer";}
};

template<>
struct symbolizer_traits<debug_symbolizer>
{
    static char const* name() { return "DebugSymbolizer";}
};

template<>
struct symbolizer_traits<dot_symbolizer>
{
    static char const* name() { return "DotSymbolizer";}
};

template<>
struct symbolizer_traits<collision_symbolizer>
{
    static char const* name() { return "CollisionSymbolizer";}
};

// symbolizer name impl
namespace detail {

struct symbolizer_name_impl
{
public:
    template <typename Symbolizer>
    std::string operator () (Symbolizer const&) const
    {
        return symbolizer_traits<Symbolizer>::name();
    }
};
}

inline std::string symbolizer_name(symbolizer const& sym)
{
    std::string type = util::apply_visitor( detail::symbolizer_name_impl(), sym);
    return type;
}

namespace {

template <typename Symbolizer, typename T>
struct set_property_impl
{
    static void apply(Symbolizer &, mapnik::keys, std::string const&)
    {
        std::cerr << "do nothing" << std::endl;
    }
};

template <typename Symbolizer>
struct set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_color> >
{
    static void apply(Symbolizer & sym, mapnik::keys key, std::string const& val)
    {
        if (boost::optional<color> c = mapnik::parse_color(val))
        {
            put(sym, key, *c);
        }
        else
        {
            throw config_error("Failed to parse color: \"" + val + "\"");
        }
    }
};

template <typename Symbolizer>
struct set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_double> >
{
    static void apply(Symbolizer &, mapnik::keys, std::string const&)
    {
        std::cerr << " expects double" << std::endl;
    }
};

template <typename Symbolizer>
struct set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_bool> >
{
    static void apply(Symbolizer &, mapnik::keys, std::string const&)
    {
        std::cerr << " expects bool" << std::endl;
    }
};

}

template <typename Symbolizer, typename T>
inline void set_property(Symbolizer & sym, mapnik::keys key, T const& val)
{
    switch (std::get<2>(get_meta(key)))
    {
    case property_types::target_bool:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_bool> >::apply(sym,key,val);
        break;
    case property_types::target_integer:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_integer> >::apply(sym,key,val);
        break;
    case property_types::target_double:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_double> >::apply(sym,key,val);
        break;
    case property_types::target_color:
        set_property_impl<Symbolizer, std::integral_constant<property_types, property_types::target_color> >::apply(sym,key,val);
        break;
    default:
        break;
    }
}

template <typename Symbolizer, typename T>
inline void set_property_from_value(Symbolizer & sym, mapnik::keys key, T const& val)
{
    switch (std::get<2>(get_meta(key)))
    {
    case property_types::target_bool:
        put(sym, key, val.to_bool());
        break;
    case property_types::target_integer:
        put(sym, key, val.to_int());
        break;
    case property_types::target_double:
        put(sym, key, val.to_double());
        break;
    case property_types::target_color:
        if (boost::optional<color> c = mapnik::parse_color(val.to_string()))
        {
            put(sym, key, *c);
        }
        else
        {
            throw config_error("Failed to parse color: \"" + val.to_string() + "\"");
        }
        break;
    default:
        break;
    }
}

namespace detail {
// helpers
template <typename Symbolizer, typename T, bool is_enum = false>
struct set_symbolizer_property_impl
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const& node)
    {
        using value_type = T;
        bool error = false;
        if (boost::optional<value_type> val = node.get_opt_attr<value_type>(name, &error))
        {
            put(sym, key, *val);
            return true;
        }
        if (error)
        {
            // try parsing as an expression
            if (boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name, &error))
            {
                // first try pre-evaluate expressions which don't have dynamic properties
                auto result = pre_evaluate_expression<mapnik::value>(*val);
                if (std::get<1>(result))
                {
                    set_property_from_value(sym, key,std::get<0>(result));
                }
                else
                {
                    // expression_ptr
                    put(sym, key, *val);
                }
                return true;
            }
            return false;
        }
        return true;
    }
};

template <typename Symbolizer>
struct set_symbolizer_property_impl<Symbolizer,transform_type,false>
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
    {
        boost::optional<std::string> transform = node.get_opt_attr<std::string>(name);
        if (transform) put(sym, key, mapnik::parse_transform(*transform));
        return true;
    }
};

template <typename Symbolizer>
struct set_symbolizer_property_impl<Symbolizer,dash_array,false>
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
    {
        boost::optional<std::string> str = node.get_opt_attr<std::string>(name);
        if (str)
        {
            dash_array dash;
            if (util::parse_dasharray(*str,dash))
            {
                put(sym,key,dash);
            }
            else
            {
                boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
                if (val)
                {
                    // first try pre-evaluate expressions which don't have dynamic properties
                    auto result = pre_evaluate_expression<mapnik::value>(*val);
                    if (std::get<1>(result))
                    {
                        set_property_from_value(sym, key,std::get<0>(result));
                    }
                    else
                    {
                        // expression_ptr
                        put(sym, key, *val);
                    }
                }
                else
                {
                    MAPNIK_LOG_ERROR(set_symbolizer_property_impl) <<
                        std::string("Failed to parse dasharray ") + "'. Expected a " +
                        "list of floats or 'none' but got '" + (*str) + "'";
                    return false;
                }
            }
        }
        return true;
    }
};

template <typename Symbolizer, typename T>
struct set_symbolizer_property_impl<Symbolizer, T, true>
{
    static bool apply(Symbolizer & sym, keys key, std::string const& name, xml_node const & node)
    {
        using value_type = T;
        boost::optional<std::string> enum_str = node.get_opt_attr<std::string>(name);
        if (enum_str)
        {
            boost::optional<value_type> enum_val = detail::enum_traits<value_type>::from_string(*enum_str);
            if (enum_val)
            {
                put(sym, key, *enum_val);
            }
            else
            {
                boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
                if (val)
                {
                    // first try pre-evaluating expression
                    auto result = pre_evaluate_expression<value>(*val);
                    if (std::get<1>(result))
                    {
                        boost::optional<value_type> enum_val2 = detail::enum_traits<value_type>::from_string(std::get<0>(result).to_string());
                        if (enum_val2)
                        {
                            put(sym, key, *enum_val);
                        }
                        else
                        {
                            // can't evaluate
                            return false;
                        }
                    }
                    else
                    {
                        // put expression_ptr
                        put(sym, key, *val);
                    }
                }
                else
                {
                    return false;
                }
            }
        }
        return true;
    }
};

} // namespace detail

template <typename Symbolizer, typename T>
void set_symbolizer_property(Symbolizer & sym, keys key, xml_node const& node)
{
    std::string const& name = std::get<0>(get_meta(key));
    if (node.has_attribute(name))
    {
        if (!detail::set_symbolizer_property_impl<Symbolizer,T, std::is_enum<T>::value>::apply(sym,key,name,node))
        {
            throw config_error("set_symbolizer_property '" + name + "'");
        }
    }
}

}

#endif // MAPNIK_SYMBOLIZER_UTILS_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_INTERNAL_PLUS_HPP
#define TAO_PEGTL_INTERNAL_PLUS_HPP

#include <type_traits>

#include "../config.hpp"

#include "opt.hpp"
#include "seq.hpp"
#include "skip_control.hpp"
#include "star.hpp"

#include "../apply_mode.hpp"
#include "../rewind_mode.hpp"
#include "../rule_list.hpp"

namespace TAO_PEGTL_NAMESPACE::internal
{
   // While plus<> could easily be implemented with
   // seq< Rule, Rules ..., star< Rule, Rules ... > > we
   // provide an explicit implementation to optimise away
   // the otherwise created input mark.

   template< typename Rule, typename... Rules >
   struct plus
      : plus< seq< Rule, Rules... > >
   {};

   template< typename Rule >
   struct plus< Rule >
   {
      using rule_t = plus;
      using subs_t = rule_list< Rule, star< Rule > >;  // TODO: Change implementation to not rely on star?

      template< apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename Input,
                typename... States >
      [[nodiscard]] static bool match( Input& in, States&&... st )
      {
         return Control< Rule >::template match< A, M, Action, Control >( in, st... ) && Control< star< Rule > >::template match< A, M, Action, Control >( in, st... );
      }
   };

   template< typename Rule, typename... Rules >
   inline constexpr bool skip_control< plus< Rule, Rules... > > = true;

}  // namespace TAO_PEGTL_NAMESPACE::internal

#endif
<commit_msg>Fix plus subs.<commit_after>// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAO_PEGTL_INTERNAL_PLUS_HPP
#define TAO_PEGTL_INTERNAL_PLUS_HPP

#include <type_traits>

#include "../config.hpp"

#include "opt.hpp"
#include "seq.hpp"
#include "skip_control.hpp"
#include "star.hpp"

#include "../apply_mode.hpp"
#include "../rewind_mode.hpp"
#include "../rule_list.hpp"

namespace TAO_PEGTL_NAMESPACE::internal
{
   // While plus<> could easily be implemented with
   // seq< Rule, Rules ..., star< Rule, Rules ... > > we
   // provide an explicit implementation to optimise away
   // the otherwise created input mark.

   template< typename Rule, typename... Rules >
   struct plus
      : plus< seq< Rule, Rules... > >
   {};

   template< typename Rule >
   struct plus< Rule >
   {
      using rule_t = plus;
      using subs_t = rule_list< Rule >;

      template< apply_mode A,
                rewind_mode M,
                template< typename... >
                class Action,
                template< typename... >
                class Control,
                typename Input,
                typename... States >
      [[nodiscard]] static bool match( Input& in, States&&... st )
      {
         if( Control< Rule >::template match< A, M, Action, Control >( in, st... ) ) {
            while( Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) {
            }
            return true;
         }
         return false;
      }
   };

   template< typename Rule, typename... Rules >
   inline constexpr bool skip_control< plus< Rule, Rules... > > = true;

}  // namespace TAO_PEGTL_NAMESPACE::internal

#endif
<|endoftext|>


<commit_before>#include "concatenate.hh"
#define AC 4

using namespace std;

void computeBackoff_enhanced(int &backlog, FIFO <Packet> &Queue, int &category, int &stickiness, std::array<int,AC> &stages,
	std::array<double,AC> &counters, int &system_stickiness, int &id, int &sx, int &ECA, std::map<double,double> &buffer){

	//CWmin values extracted from Perahia & Stacey's: Next Generation Wireless LANs (p. 240)
	int CWmin [4] = { 32, 32, 16, 8 };

	// int CWmin [4] = { 64, 64, 32, 16 };
	// int CWmin [4] = { 1024, 1024, 1024, 1024 };

	double deterministicBackoff;
	double randomBackoff;
	std::array<int, AC> futureCycles;
	std::array<int, AC> compareBackoffs;
	std::array<int, AC> compareCycles;
	std::array<int, AC> match;
	std::map<double,double>::iterator it;

	deterministicBackoff = (int) (pow(2,(stages.at(category))) * CWmin[category]/2 - 1);
	match.fill(0);
	futureCycles.fill(1);
	compareBackoffs.fill(1);
	compareBackoffs.fill(1);

	//Looking for an appropriate random backoff in the buffer
	//to avoid repeating the computation everytime.

	unsigned hash1 = concatenate(counters.at(0), counters.at(1));
	// cout << "hash1: " << hash1;
	unsigned hash2 = concatenate(counters.at(2), counters.at(3));
	// cout << ". hash2: " << hash2;
	unsigned hash = concatenate(hash1, hash2);
	// cout << ". hash: " << hash;
	hash = concatenate(hash, (unsigned)stages.at(category));
	// cout << ". final: " << hash << endl;
	it = buffer.find(hash);

	if(it == buffer.end())	//If hash is not in buffer
	{
		// cout << "Not in buffer: " << hash << endl;
		while ( (compareBackoffs != match) || (compareCycles != match) )
		{
			randomBackoff = rand() % (int) ( (pow(2,stages.at(category))) * CWmin[category] - 1);
			if(randomBackoff == 0) randomBackoff++;

			//Avoiding internal collisions with the randomBackoff
			for(int i = 0; i < AC; i++)
			{
				//Checking if the randomBackoff will collide with successful ACs
				if(i != category)
				{
					int difference = fabs( (pow(2,stages.at(i)) * CWmin[i]/2 -1) - randomBackoff);
					int minimum = std::min( (pow(2,stages.at(i)) * CWmin[i]/2 -1), randomBackoff );
					futureCycles.at(i) = difference % minimum;
				}
			}

			//Filling arrays to make a decision over the chosen random backoff
			for(int i = 0; i < AC; i++)
			{
				if(randomBackoff == counters.at(i))
				{
					compareBackoffs.at(i) = 1;
				}else
				{
					compareBackoffs.at(i) = 0;
				}

				if(futureCycles.at(i) == 0)
				{
					compareCycles.at(i) = 1;
				}else
				{
					compareCycles.at(i) = 0;
				}

			}
		}
		buffer[hash] = randomBackoff;
		// cout << "Adding it: " << buffer[hash] << endl;
	}else
	{
		randomBackoff = it->second;	//second value pointed by the iterator. That is, the value.
		// cout << "Buffered [" << it->first << "]: " << it->second << endl;
	}

	//Assigning the backoff to the correspondent AC

	if(backlog == 1)
	{
		// cout << "Node " << id << ". AC " << category << " Old counter: " << counters.at(category) << endl;
		if(sx == 1)
		{
			if(ECA == 1)
			{
				counters.at(category) = deterministicBackoff;
				// cout << "+++Node " << id << " AC " << category << " ECA: " << counters.at(category) << endl;
			}else
			{
				counters.at(category) = randomBackoff;
				// cout << "---Node " << id << " AC " << category << " DCF: " << counters.at(category) << endl;
			}
		}else
		{
			if(stickiness > 0)
			{
				counters.at(category) = deterministicBackoff;
				// cout << "+++Node " << id << " AC " << category << " ECA (hyst): " << counters.at(category) << endl;
			}else
			{
				counters.at(category) = randomBackoff;
				// cout << "---Node " << id << " AC " << category << " DCF (col): " << counters.at(category) << endl;
			}

		}
	}else
	{
		stages.at(category) = 0;
		counters.at(category) = 0;
		stickiness = system_stickiness;
		// cout << "\tAC " << category << " has an empty queue" << endl;
	}
}<commit_msg>Fixed an issue when computing the SmartBackoff<commit_after>#include "concatenate.hh"
#define AC 4

using namespace std;

void computeBackoff_enhanced(int &backlog, FIFO <Packet> &Queue, int &category, int &stickiness, std::array<int,AC> &stages,
	std::array<double,AC> &counters, int &system_stickiness, int &id, int &sx, int &ECA, std::map<double,double> &buffer){

	//CWmin values extracted from Perahia & Stacey's: Next Generation Wireless LANs (p. 240)
	int CWmin [4] = { 32, 32, 16, 8 };

	// int CWmin [4] = { 64, 64, 32, 16 };
	// int CWmin [4] = { 1024, 1024, 1024, 1024 };

	double deterministicBackoff;
	double randomBackoff;
	std::array<int, AC> futureCycles;
	std::array<int, AC> compareBackoffs;
	std::array<int, AC> compareCycles;
	std::array<int, AC> match;
	std::map<double,double>::iterator it;

	deterministicBackoff = (int) (pow(2,(stages.at(category))) * CWmin[category]/2 - 1);
	match.fill(0);
	futureCycles.fill(1);
	compareBackoffs.fill(1);
	compareBackoffs.fill(1);

	//Looking for an appropriate random backoff in the buffer
	//to avoid repeating the computation everytime.

	unsigned hash1 = concatenate(counters.at(0), counters.at(1));
	// cout << "hash1: " << hash1;
	unsigned hash2 = concatenate(counters.at(2), counters.at(3));
	// cout << ". hash2: " << hash2;
	unsigned hash = concatenate(hash1, hash2);
	// cout << ". hash: " << hash;
	hash = concatenate(hash, (unsigned)stages.at(category));
	// cout << ". final: " << hash << endl;
	it = buffer.find(hash);

	if(it == buffer.end())	//If hash is not in buffer
	{
		// cout << "Not in buffer: " << hash << endl;
		while ( (compareBackoffs != match) || (compareCycles != match) )
		{
			randomBackoff = rand() % (int) ( (pow(2,stages.at(category))) * CWmin[category] - 1);
			if(randomBackoff == 0) randomBackoff++;

			//Avoiding internal collisions with the randomBackoff
			for(int i = 0; i < AC; i++)
			{
				//Checking if the randomBackoff will collide with successful ACs
				if(i != category)
				{
					int difference = fabs( (pow(2,stages.at(i)) * CWmin[i]/2 -1) - randomBackoff);
					int minimum = std::min( (pow(2,stages.at(i)) * CWmin[i]/2 -1), deterministicBackoff );
					futureCycles.at(i) = difference % minimum;
				}
			}

			//Filling arrays to make a decision over the chosen random backoff
			for(int i = 0; i < AC; i++)
			{
				if(randomBackoff == counters.at(i))
				{
					compareBackoffs.at(i) = 1;
				}else
				{
					compareBackoffs.at(i) = 0;
				}

				if(futureCycles.at(i) == 0)
				{
					compareCycles.at(i) = 1;
				}else
				{
					compareCycles.at(i) = 0;
				}

			}
		}
		buffer[hash] = randomBackoff;
		// cout << "Adding it: " << buffer[hash] << endl;
	}else
	{
		randomBackoff = it->second;	//second value pointed by the iterator. That is, the value.
		// cout << "Buffered [" << it->first << "]: " << it->second << endl;
	}

	//Assigning the backoff to the correspondent AC

	if(backlog == 1)
	{
		// cout << "Node " << id << ". AC " << category << " Old counter: " << counters.at(category) << endl;
		if(sx == 1)
		{
			if(ECA == 1)
			{
				counters.at(category) = deterministicBackoff;
				// cout << "+++Node " << id << " AC " << category << " ECA: " << counters.at(category) << endl;
			}else
			{
				counters.at(category) = randomBackoff;
				// cout << "---Node " << id << " AC " << category << " DCF: " << counters.at(category) << endl;
			}
		}else
		{
			if(stickiness > 0)
			{
				counters.at(category) = deterministicBackoff;
				// cout << "+++Node " << id << " AC " << category << " ECA (hyst): " << counters.at(category) << endl;
			}else
			{
				counters.at(category) = randomBackoff;
				// cout << "---Node " << id << " AC " << category << " DCF (col): " << counters.at(category) << endl;
			}

		}
	}else
	{
		stages.at(category) = 0;
		counters.at(category) = 0;
		stickiness = system_stickiness;
		// cout << "\tAC " << category << " has an empty queue" << endl;
	}
}<|endoftext|>