<commit_before>#include "stdafx.h"
#include "UICurve.h"
#include "../resource/ResManager.h"

using namespace Gear::Res;

UICurve::UICurve()
#ifdef USE_D2D_RENDER_MODE
	:m_pColorBrush(nullptr)
	, m_pStrokeStyle(nullptr)
#else

#endif
{
	InitAttrMap();
	InitEventMap();
	InitAttrValuePatternMap();
	InitAttrValueParserMap();
}
void UICurve::InitAttrMap()
{
	ADD_ATTR("color",	"FFFFFF")
	ADD_ATTR("hline",	"0")
	ADD_ATTR("vline", "0")
	ADD_ATTR("linewidth", "1")
	ADD_ATTR("style", "solid")
	ADD_ATTR("cap", "flat")
	ADD_ATTR("dashes", "")//ֻstyle == customʱŻõ
}
void UICurve::InitEventMap()
{

}
void UICurve::InitAttrValuePatternMap()
{
	ADD_ATTR_PATTERN("color",	R_CHECK_COLOR_VALUE)
	ADD_ATTR_PATTERN("hline",	R_CHECK_BOOL)
	ADD_ATTR_PATTERN("vline", R_CHECK_BOOL)
	ADD_ATTR_PATTERN("linewidth", R_CHECK_INT)
}
void UICurve::InitAttrValueParserMap()
{
	auto ParseDashes = [&](const string& sAttrName)->bool {
		string dashes = m_attrMap[sAttrName];
		if (dashes.empty()){
			return false;
		}
		EraseSpace(dashes);
		string item = "";
		for (std::size_t i=0; i<dashes.length(); ++i)
		{
			char num = dashes[i];
			if (num >= '0' && num <= '9')
			{
				item += num;
			} else if(num == ','){
				float dash = (float)atoi(item.c_str());
				item = "";
				m_dashesVec.push_back(dash);
				continue;
			} else {
				ERR("ParseDashes error: illegal character");
				return false;
			}
		}
		if (!item.empty())
		{
			float dash = (float)atoi(item.c_str());
			m_dashesVec.push_back(dash);
		}
		return true;
	};

	ADD_ATTR_PARSER("dashes", ParseDashes)
}

///////////////////////////////////////Direct2DȾģʽش///////////////////////////////////
#ifdef USE_D2D_RENDER_MODE
HRESULT	UICurve::OnDrawImpl(ID2D1RenderTarget* pRenderTarget, const D2D1_RECT_F& rcWndPos)
{
	HRESULT hr = S_OK;
	D2D1_POINT_2F pA, pB;
	int lineWidth = atoi(m_attrMap["linewidth"].c_str());

	if (m_attrMap["hline"] == "1") {
		pA.x = rcWndPos.left;
		pA.y = rcWndPos.top;
		pB.x = rcWndPos.right;
		pB.y = rcWndPos.top;
		pRenderTarget->DrawLine(pA, pB, m_pColorBrush, (FLOAT)lineWidth, m_pStrokeStyle);
	} else if (m_attrMap["vline"] == "1") {
		pA.x = rcWndPos.left;
		pA.y = rcWndPos.top;
		pB.x = rcWndPos.left;
		pB.y = rcWndPos.bottom;
		pRenderTarget->DrawLine(pA, pB, m_pColorBrush, (FLOAT)lineWidth, m_pStrokeStyle);
	} else {//if(m_gdiPointsVer.size() > 0)
		m_pointsVer.push_back(D2D1_POINT_2F{ 0, 0 });
		m_pointsVer.push_back(D2D1_POINT_2F{ 15, 5 });
		m_pointsVer.push_back(D2D1_POINT_2F{ 70, 9 });
		m_pointsVer.push_back(D2D1_POINT_2F{ 11, 50 });
		std::size_t length = m_pointsVer.size();

		for (std::size_t i = 0; i < length - 1; ++i) {
			pA = m_pointsVer[i];
			pB = m_pointsVer[i + 1];
			pRenderTarget->DrawLine(pA, pB, m_pColorBrush, (FLOAT)lineWidth, m_pStrokeStyle);
		}
	}
	return hr;
}
HRESULT	UICurve::CreateDeviceDependentResources(ID2D1RenderTarget* pRenderTarget)
{
	if (m_pColorBrush) return S_OK;

	if (!pRenderTarget) {
		ERR("fatal error in CreateDeviceDependentResources, nullptr! OnDrawImpl will abort");
		return S_FALSE;
	}

	D2D1::ColorF curveColor = ResManager::GetInstance().GetColorObject(m_attrMap["color"])->GetD2D1ColorF();
	HRESULT hr = pRenderTarget->CreateSolidColorBrush(curveColor, &m_pColorBrush);
	if (FAILED(hr)) {
		ERR("fatal error in CreateSolidColorBrush, nullptr! hr:{}", hr);
		return hr;
	}

	//Ĭsolid(ʵ)
	D2D1_STROKE_STYLE_PROPERTIES prop = StrokeStyleProperties();
	auto style = m_attrMap["style"];
	auto cap = m_attrMap["cap"];
	int length = 0;
	FLOAT* floatVec = nullptr;
	if (style == "solid") {
		prop.dashStyle = D2D1_DASH_STYLE_SOLID;
	}else if (style == "dash") {
		prop.dashStyle = D2D1_DASH_STYLE_DASH;
	} else if (style == "dot") {
		prop.dashStyle = D2D1_DASH_STYLE_DOT;
	} else if (style == "dashdot") {
		prop.dashStyle = D2D1_DASH_STYLE_DASH_DOT;
	} else if (style == "dashdotdot") {
		prop.dashStyle = D2D1_DASH_STYLE_DASH_DOT_DOT;
	} else if (style == "custom" && m_dashesVec.size() > 0) {
		prop.dashStyle = D2D1_DASH_STYLE_CUSTOM;
		length = m_dashesVec.size();
		floatVec = new FLOAT[length];
		for (auto i=0; i<length; ++i)
		{
			floatVec[i] = m_dashesVec[i];
		}
	}

	if (cap == "flat") {
		prop.dashCap = D2D1_CAP_STYLE_FLAT;
	} else if (cap == "square") {
		prop.dashCap = D2D1_CAP_STYLE_SQUARE;
	} else if (cap == "round") {
		prop.dashCap = D2D1_CAP_STYLE_ROUND;
	} else if (cap == "triangle") {
		prop.dashCap = D2D1_CAP_STYLE_TRIANGLE;
	}

	hr = RenderManager::m_pD2DFactory->CreateStrokeStyle(prop, floatVec, length,&m_pStrokeStyle);
	if (FAILED(hr)) {
		ERR("fatal error in m_pStrokeStyle, nullptr! hr:{}", hr);
		return hr;
	}
	return hr;
}
HRESULT	UICurve::DiscardDeviceDependentResources()
{
	HRESULT hr = S_OK;
	SafeRelease(&m_pColorBrush);
	SafeRelease(&m_pStrokeStyle);
	return hr;
}
/////////////////////////////////////////GDI+Ⱦģʽش/////////////////////////////////////
#else
HRESULT	UICurve::OnDrawImpl(Graphics& graphics, const UIPos& rcWndPos)
{
	auto SetStyle = [&](Pen& pen) {
		auto style = m_attrMap["style"];
		if (style == "solid") {
			pen.SetDashStyle(DashStyleSolid);
		} else if (style == "dash") {
			pen.SetDashStyle(DashStyleDash);
		} else if (style == "dot") {
			pen.SetDashStyle(DashStyleDot);
		} else if (style == "dashdot") {
			pen.SetDashStyle(DashStyleDashDot);
		} else if (style == "dashdotdot") {
			pen.SetDashStyle(DashStyleDashDotDot);
		} else if (style == "custom") {
			pen.SetDashStyle(DashStyleCustom);

			int length = (int)m_dashesVec.size();
			REAL* floatVec = new REAL[length];
			for (auto i = 0; i < length; ++i)
			{
				floatVec[i] = m_dashesVec[i];
			}
			pen.SetDashPattern(floatVec, length);
		}
	};

	auto SetCap = [&](Pen& pen) {
		auto cap = m_attrMap["cap"];
		if (cap == "flat") {
			pen.SetDashCap(Gdiplus::DashCapFlat);
		} else if (cap == "round") {
			pen.SetDashCap(Gdiplus::DashCapRound);
		} else if (cap == "triangle") {
			pen.SetDashCap(Gdiplus::DashCapTriangle);
		}
	};

	ResColor* resColorObj = ResManager::GetInstance().GetColorObject(m_attrMap["color"]);
	Color color = resColorObj->GetGdiplusColor();
	int lineWidth = atoi(m_attrMap["linewidth"].c_str());
	Gdiplus::Pen pen(color, (REAL)lineWidth);

	SetStyle(pen);
	SetCap(pen);

	Status status = GenericError;
	if (m_attrMap["hline"] == "1"){
		Gdiplus::Point pA(rcWndPos.left, rcWndPos.top);
		Gdiplus::Point pB(rcWndPos.left + rcWndPos.width, rcWndPos.top);
		status = graphics.DrawLine(&pen, pA, pB);
	} else if(m_attrMap["vline"] == "1") {
		Gdiplus::Point pA(rcWndPos.left, rcWndPos.top);
		Gdiplus::Point pB(rcWndPos.left, rcWndPos.top + rcWndPos.height);
		status = graphics.DrawLine(&pen, pA, pB);
	} else  {//if(m_gdiPointsVer.size() > 0)
		m_pointsVer.push_back(PointF(0, 0));
		m_pointsVer.push_back(PointF(15, 5));
		m_pointsVer.push_back(PointF(70, 9));
		m_pointsVer.push_back(PointF(11, 50));
		std::size_t length = m_pointsVer.size();
		Gdiplus::PointF* points = new Gdiplus::PointF[length];
		for (std::size_t i=0; i<length; ++i){
			points[i] = m_pointsVer[i];
		}
		status = graphics.DrawLines(&pen, points, length);
	}
	return status == Ok ? S_OK : S_FALSE;
}
#endif<commit_msg>去掉测试代码<commit_after>#include "stdafx.h"
#include "UICurve.h"
#include "../resource/ResManager.h"

using namespace Gear::Res;

UICurve::UICurve()
#ifdef USE_D2D_RENDER_MODE
	:m_pColorBrush(nullptr)
	, m_pStrokeStyle(nullptr)
#else

#endif
{
	InitAttrMap();
	InitEventMap();
	InitAttrValuePatternMap();
	InitAttrValueParserMap();
}
void UICurve::InitAttrMap()
{
	ADD_ATTR("color",	"FFFFFF")
	ADD_ATTR("hline",	"0")
	ADD_ATTR("vline", "0")
	ADD_ATTR("linewidth", "1")
	ADD_ATTR("style", "solid")
	ADD_ATTR("cap", "flat")
	ADD_ATTR("dashes", "")//ֻstyle == customʱŻõ
}
void UICurve::InitEventMap()
{

}
void UICurve::InitAttrValuePatternMap()
{
	ADD_ATTR_PATTERN("color",	R_CHECK_COLOR_VALUE)
	ADD_ATTR_PATTERN("hline",	R_CHECK_BOOL)
	ADD_ATTR_PATTERN("vline", R_CHECK_BOOL)
	ADD_ATTR_PATTERN("linewidth", R_CHECK_INT)
}
void UICurve::InitAttrValueParserMap()
{
	auto ParseDashes = [&](const string& sAttrName)->bool {
		string dashes = m_attrMap[sAttrName];
		if (dashes.empty()){
			return false;
		}
		EraseSpace(dashes);
		string item = "";
		for (std::size_t i=0; i<dashes.length(); ++i)
		{
			char num = dashes[i];
			if (num >= '0' && num <= '9')
			{
				item += num;
			} else if(num == ','){
				float dash = (float)atoi(item.c_str());
				item = "";
				m_dashesVec.push_back(dash);
				continue;
			} else {
				ERR("ParseDashes error: illegal character");
				return false;
			}
		}
		if (!item.empty())
		{
			float dash = (float)atoi(item.c_str());
			m_dashesVec.push_back(dash);
		}
		return true;
	};

	ADD_ATTR_PARSER("dashes", ParseDashes)
}

///////////////////////////////////////Direct2DȾģʽش///////////////////////////////////
#ifdef USE_D2D_RENDER_MODE
HRESULT	UICurve::OnDrawImpl(ID2D1RenderTarget* pRenderTarget, const D2D1_RECT_F& rcWndPos)
{
	HRESULT hr = S_OK;
	D2D1_POINT_2F pA, pB;
	int lineWidth = atoi(m_attrMap["linewidth"].c_str());

	if (m_attrMap["hline"] == "1") {
		pA.x = rcWndPos.left;
		pA.y = rcWndPos.top;
		pB.x = rcWndPos.right;
		pB.y = rcWndPos.top;
		pRenderTarget->DrawLine(pA, pB, m_pColorBrush, (FLOAT)lineWidth, m_pStrokeStyle);
	} else if (m_attrMap["vline"] == "1") {
		pA.x = rcWndPos.left;
		pA.y = rcWndPos.top;
		pB.x = rcWndPos.left;
		pB.y = rcWndPos.bottom;
		pRenderTarget->DrawLine(pA, pB, m_pColorBrush, (FLOAT)lineWidth, m_pStrokeStyle);
	} else if (m_pointsVer.size() > 0) {//
		std::size_t length = m_pointsVer.size();

		for (std::size_t i = 0; i < length - 1; ++i) {
			pA = m_pointsVer[i];
			pB = m_pointsVer[i + 1];
			pRenderTarget->DrawLine(pA, pB, m_pColorBrush, (FLOAT)lineWidth, m_pStrokeStyle);
		}
	}
	return hr;
}
HRESULT	UICurve::CreateDeviceDependentResources(ID2D1RenderTarget* pRenderTarget)
{
	if (m_pColorBrush) return S_OK;

	if (!pRenderTarget) {
		ERR("fatal error in CreateDeviceDependentResources, nullptr! OnDrawImpl will abort");
		return S_FALSE;
	}

	D2D1::ColorF curveColor = ResManager::GetInstance().GetColorObject(m_attrMap["color"])->GetD2D1ColorF();
	HRESULT hr = pRenderTarget->CreateSolidColorBrush(curveColor, &m_pColorBrush);
	if (FAILED(hr)) {
		ERR("fatal error in CreateSolidColorBrush, nullptr! hr:{}", hr);
		return hr;
	}

	//Ĭsolid(ʵ)
	D2D1_STROKE_STYLE_PROPERTIES prop = StrokeStyleProperties();
	auto style = m_attrMap["style"];
	auto cap = m_attrMap["cap"];
	int length = 0;
	FLOAT* floatVec = nullptr;
	if (style == "solid") {
		prop.dashStyle = D2D1_DASH_STYLE_SOLID;
	}else if (style == "dash") {
		prop.dashStyle = D2D1_DASH_STYLE_DASH;
	} else if (style == "dot") {
		prop.dashStyle = D2D1_DASH_STYLE_DOT;
	} else if (style == "dashdot") {
		prop.dashStyle = D2D1_DASH_STYLE_DASH_DOT;
	} else if (style == "dashdotdot") {
		prop.dashStyle = D2D1_DASH_STYLE_DASH_DOT_DOT;
	} else if (style == "custom" && m_dashesVec.size() > 0) {
		prop.dashStyle = D2D1_DASH_STYLE_CUSTOM;
		length = m_dashesVec.size();
		floatVec = new FLOAT[length];
		for (auto i=0; i<length; ++i)
		{
			floatVec[i] = m_dashesVec[i];
		}
	}

	if (cap == "flat") {
		prop.dashCap = D2D1_CAP_STYLE_FLAT;
	} else if (cap == "square") {
		prop.dashCap = D2D1_CAP_STYLE_SQUARE;
	} else if (cap == "round") {
		prop.dashCap = D2D1_CAP_STYLE_ROUND;
	} else if (cap == "triangle") {
		prop.dashCap = D2D1_CAP_STYLE_TRIANGLE;
	}

	hr = RenderManager::m_pD2DFactory->CreateStrokeStyle(prop, floatVec, length,&m_pStrokeStyle);
	if (FAILED(hr)) {
		ERR("fatal error in m_pStrokeStyle, nullptr! hr:{}", hr);
		return hr;
	}
	return hr;
}
HRESULT	UICurve::DiscardDeviceDependentResources()
{
	HRESULT hr = S_OK;
	SafeRelease(&m_pColorBrush);
	SafeRelease(&m_pStrokeStyle);
	return hr;
}
/////////////////////////////////////////GDI+Ⱦģʽش/////////////////////////////////////
#else
HRESULT	UICurve::OnDrawImpl(Graphics& graphics, const UIPos& rcWndPos)
{
	auto SetStyle = [&](Pen& pen) {
		auto style = m_attrMap["style"];
		if (style == "solid") {
			pen.SetDashStyle(DashStyleSolid);
		} else if (style == "dash") {
			pen.SetDashStyle(DashStyleDash);
		} else if (style == "dot") {
			pen.SetDashStyle(DashStyleDot);
		} else if (style == "dashdot") {
			pen.SetDashStyle(DashStyleDashDot);
		} else if (style == "dashdotdot") {
			pen.SetDashStyle(DashStyleDashDotDot);
		} else if (style == "custom") {
			pen.SetDashStyle(DashStyleCustom);

			int length = (int)m_dashesVec.size();
			REAL* floatVec = new REAL[length];
			for (auto i = 0; i < length; ++i)
			{
				floatVec[i] = m_dashesVec[i];
			}
			pen.SetDashPattern(floatVec, length);
		}
	};

	auto SetCap = [&](Pen& pen) {
		auto cap = m_attrMap["cap"];
		if (cap == "flat") {
			pen.SetDashCap(Gdiplus::DashCapFlat);
		} else if (cap == "round") {
			pen.SetDashCap(Gdiplus::DashCapRound);
		} else if (cap == "triangle") {
			pen.SetDashCap(Gdiplus::DashCapTriangle);
		}
	};

	ResColor* resColorObj = ResManager::GetInstance().GetColorObject(m_attrMap["color"]);
	Color color = resColorObj->GetGdiplusColor();
	int lineWidth = atoi(m_attrMap["linewidth"].c_str());
	Gdiplus::Pen pen(color, (REAL)lineWidth);

	SetStyle(pen);
	SetCap(pen);

	Status status = GenericError;
	if (m_attrMap["hline"] == "1"){
		Gdiplus::Point pA(rcWndPos.left, rcWndPos.top);
		Gdiplus::Point pB(rcWndPos.left + rcWndPos.width, rcWndPos.top);
		status = graphics.DrawLine(&pen, pA, pB);
	} else if(m_attrMap["vline"] == "1") {
		Gdiplus::Point pA(rcWndPos.left, rcWndPos.top);
		Gdiplus::Point pB(rcWndPos.left, rcWndPos.top + rcWndPos.height);
		status = graphics.DrawLine(&pen, pA, pB);
	} else if (m_pointsVer.size() > 0) {//
		std::size_t length = m_pointsVer.size();
		Gdiplus::PointF* points = new Gdiplus::PointF[length];
		for (std::size_t i=0; i<length; ++i){
			points[i] = m_pointsVer[i];
		}
		status = graphics.DrawLines(&pen, points, length);
	}
	return status == Ok ? S_OK : S_FALSE;
}
#endif<|endoftext|>


<commit_before>#ifndef DATAMANAGER_H
#define DATAMANAGER_H

#include "StdIncl.hpp"
#include "types/Data.hpp"
#include "InvalidConfigException.hpp"

namespace uipf{
using namespace std;

// Provides and controls access to Parameters, Input and Outputdata
class DataManager
{

	public:
		DataManager(std::map < std::string, Data::ptr& >& input, std::map < std::string,std::string >& params, std::map < std::string, Data::ptr >& output)
	:input_(input),params_(params),output_(output)
	{}

		~DataManager(){}

		//returns a typesafe readonly smartpointer to input/output data by name if it is available
		template <typename T>
		const T* getInputData( const std::string& strName) const;

		//returns a typesafe smartpointer to input/output data by name if it is available
		template <typename T>
		T* getOutputData( const std::string& strName) const;

		//returns a typesafe smartpointer to input/output data by name if it is available
		template <typename T>
		void setOutputData( const std::string& strName, T*) ;

		//returns a typesafe parameter by name if it is available. otherwise a defaultValue is used
		template <typename T>
		T getParam(const std::string& strName, T defaultValue) const;

		//print given parameters
		void listParams( ) const;

	private:
		std::map < std::string, Data::ptr& >& input_;
		std::map < std::string, std::string >& params_;
		std::map < std::string, Data::ptr >& output_;

};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//templates need to be implemented in headers

template <typename T>
const T* DataManager::getInputData( const std::string& strName) const
{
	if (input_.find(strName) != input_.end())
	{
		//do downcasting..
		Data::ptr& ptr = input_.find(strName)->second;
		return dynamic_cast<T*>(ptr.get());
	}
	else
	{
		throw InvalidConfigException(std::string("input data '") + strName + std::string("' not found!"));
	}
}

template <typename T>
T* DataManager::getOutputData( const std::string& strName) const
{
	if (output_.find(strName) != output_.end())
	{
		//do downcasting..
		Data::ptr& ptr = output_.find(strName)->second;
		return dynamic_cast<T*>(ptr.get());
	}
	else
	{
		throw InvalidConfigException(std::string("input data '") + strName + std::string("' not found!"));
	}
}

template <typename T>
void DataManager::setOutputData( const std::string& strName, T* outputData)
{
	output_.insert (pair < string, Data::ptr >(strName, typename T::ptr(outputData)));
}

//2DO other type specialisations e.g. float with atof() etc.
template <typename T>
T DataManager::getParam( const std::string& strName, T defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return static_cast<T>(params_[strName]);
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline int DataManager::getParam( const std::string& strName, int defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return atoi(params_[strName].c_str());
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline float DataManager::getParam(const std::string& strName, float defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return atof(params_[strName].c_str());
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline double DataManager::getParam( const std::string& strName, double defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return atof(params_[strName].c_str());
	}
	else
	{
		return defaultValue;
	}
}

} //namespace

#endif // DATAMANAGER_H

<commit_msg>parsing for bools from yaml<commit_after>#ifndef DATAMANAGER_H
#define DATAMANAGER_H

#include "StdIncl.hpp"
#include "types/Data.hpp"
#include "InvalidConfigException.hpp"
#include "Utils.hpp"

namespace uipf{
using namespace std;

// Provides and controls access to Parameters, Input and Outputdata
class DataManager
{

	public:
		DataManager(std::map < std::string, Data::ptr& >& input, std::map < std::string,std::string >& params, std::map < std::string, Data::ptr >& output)
	:input_(input),params_(params),output_(output)
	{}

		~DataManager(){}

		//returns a typesafe readonly smartpointer to input/output data by name if it is available
		template <typename T>
		const T* getInputData( const std::string& strName) const;

		//returns a typesafe smartpointer to input/output data by name if it is available
		template <typename T>
		T* getOutputData( const std::string& strName) const;

		//returns a typesafe smartpointer to input/output data by name if it is available
		template <typename T>
		void setOutputData( const std::string& strName, T*) ;

		//returns a typesafe parameter by name if it is available. otherwise a defaultValue is used
		template <typename T>
		T getParam(const std::string& strName, T defaultValue) const;

		//print given parameters
		void listParams( ) const;

	private:
		std::map < std::string, Data::ptr& >& input_;
		std::map < std::string, std::string >& params_;
		std::map < std::string, Data::ptr >& output_;

};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//templates need to be implemented in headers

template <typename T>
const T* DataManager::getInputData( const std::string& strName) const
{
	if (input_.find(strName) != input_.end())
	{
		//do downcasting..
		Data::ptr& ptr = input_.find(strName)->second;
		return dynamic_cast<T*>(ptr.get());
	}
	else
	{
		throw InvalidConfigException(std::string("input data '") + strName + std::string("' not found!"));
	}
}

template <typename T>
T* DataManager::getOutputData( const std::string& strName) const
{
	if (output_.find(strName) != output_.end())
	{
		//do downcasting..
		Data::ptr& ptr = output_.find(strName)->second;
		return dynamic_cast<T*>(ptr.get());
	}
	else
	{
		throw InvalidConfigException(std::string("input data '") + strName + std::string("' not found!"));
	}
}

template <typename T>
void DataManager::setOutputData( const std::string& strName, T* outputData)
{
	output_.insert (pair < string, Data::ptr >(strName, typename T::ptr(outputData)));
}

//2DO other type specialisations e.g. float with atof() etc.
template <typename T>
T DataManager::getParam( const std::string& strName, T defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return static_cast<T>(params_[strName]);
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline int DataManager::getParam( const std::string& strName, int defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return atoi(params_[strName].c_str());
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline float DataManager::getParam(const std::string& strName, float defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return atof(params_[strName].c_str());
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline double DataManager::getParam( const std::string& strName, double defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return atof(params_[strName].c_str());
	}
	else
	{
		return defaultValue;
	}
}

template <>
inline bool DataManager::getParam( const std::string& strName, bool defaultValue) const
{
	if (params_.find(strName) != params_.end())
	{
		return (utils::toLower(params_[strName]).compare("true")==0);
	}
	else
	{
		return defaultValue;
	}
}

} //namespace

#endif // DATAMANAGER_H

<|endoftext|>


<commit_before>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "SessionSetup/RetrieveInstancesWidget.h"

#include <QCoreApplication>
#include <QLineEdit>
#include <QMessageBox>
#include <QObject>
#include <QPointer>
#include <QPushButton>
#include <QSettings>
#include <QVariant>
#include <memory>
#include <optional>

#include "MetricsUploader/ScopedMetric.h"
#include "MetricsUploader/orbit_log_event.pb.h"
#include "OrbitBase/Result.h"
#include "OrbitGgp/Client.h"
#include "QtUtils/MainThreadExecutorImpl.h"
#include "SessionSetup/PersistentStorage.h"
#include "SessionSetup/RetrieveInstances.h"
#include "ui_RetrieveInstancesWidget.h"

namespace orbit_session_setup {

using orbit_ggp::Instance;
using orbit_ggp::Project;
using LoadProjectsAndInstancesResult = RetrieveInstances::LoadProjectsAndInstancesResult;
using InstanceListScope = orbit_ggp::Client::InstanceListScope;
using orbit_metrics_uploader::OrbitLogEvent;
using orbit_metrics_uploader::ScopedMetric;

RetrieveInstancesWidget::~RetrieveInstancesWidget() = default;

RetrieveInstancesWidget::RetrieveInstancesWidget(QWidget* parent)
    : QWidget(parent),
      ui_(std::make_unique<Ui::RetrieveInstancesWidget>()),
      main_thread_executor_(orbit_qt_utils::MainThreadExecutorImpl::Create()),
      s_idle_(&state_machine_),
      s_loading_(&state_machine_),
      s_initial_loading_failed_(&state_machine_) {
  ui_->setupUi(this);

  SetupStateMachine();

  QObject::connect(ui_->filterLineEdit, &QLineEdit::textChanged, this,
                   &RetrieveInstancesWidget::FilterTextChanged);
  QObject::connect(ui_->reloadButton, &QPushButton::clicked, this,
                   &RetrieveInstancesWidget::OnReloadButtonClicked);
  QObject::connect(ui_->projectComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
                   &RetrieveInstancesWidget::OnProjectComboBoxCurrentIndexChanged);
  QObject::connect(ui_->allCheckBox, &QCheckBox::clicked, this,
                   &RetrieveInstancesWidget::OnAllCheckboxClicked);
}

void RetrieveInstancesWidget::SetupStateMachine() {
  state_machine_.setGlobalRestorePolicy(QStateMachine::RestoreProperties);

  s_idle_.assignProperty(ui_->projectComboBox, "enabled", true);
  s_idle_.assignProperty(ui_->filterLineEdit, "enabled", true);
  s_idle_.assignProperty(ui_->allCheckBox, "enabled", true);
  s_idle_.assignProperty(ui_->reloadButton, "enabled", true);
  s_idle_.addTransition(this, &RetrieveInstancesWidget::LoadingStarted, &s_loading_);

  s_loading_.assignProperty(ui_->projectComboBox, "enabled", false);
  s_loading_.assignProperty(ui_->filterLineEdit, "enabled", false);
  s_loading_.assignProperty(ui_->allCheckBox, "enabled", false);
  s_loading_.assignProperty(ui_->reloadButton, "enabled", false);
  s_loading_.addTransition(this, &RetrieveInstancesWidget::LoadingSuccessful, &s_idle_);
  s_loading_.addTransition(this, &RetrieveInstancesWidget::LoadingFailed, &s_idle_);
  s_loading_.addTransition(this, &RetrieveInstancesWidget::InitialLoadingFailed,
                           &s_initial_loading_failed_);

  s_initial_loading_failed_.assignProperty(ui_->projectComboBox, "enabled", false);
  s_initial_loading_failed_.assignProperty(ui_->filterLineEdit, "enabled", false);
  s_initial_loading_failed_.assignProperty(ui_->allCheckBox, "enabled", false);
  s_initial_loading_failed_.assignProperty(ui_->reloadButton, "enabled", true);
  s_initial_loading_failed_.addTransition(this, &RetrieveInstancesWidget::LoadingStarted,
                                          &s_loading_);
}

void RetrieveInstancesWidget::Start() {
  ORBIT_CHECK(retrieve_instances_ != nullptr);
  state_machine_.setInitialState(&s_loading_);
  state_machine_.start();

  ui_->allCheckBox->setChecked(LoadInstancesScopeFromPersistentStorage() ==
                               InstanceListScope::kAllReservedInstances);

  InitialLoad(LoadLastSelectedProjectFromPersistentStorage());
}

InstanceListScope RetrieveInstancesWidget::GetSelectedInstanceListScope() const {
  return ui_->allCheckBox->isChecked() ? InstanceListScope::kAllReservedInstances
                                       : InstanceListScope::kOnlyOwnInstances;
}

void RetrieveInstancesWidget::InitialLoad(const std::optional<Project>& remembered_project) {
  ORBIT_CHECK(ui_->projectComboBox->count() == 0);
  emit LoadingStarted();
  ScopedMetric metric{metrics_uploader_, OrbitLogEvent::ORBIT_INSTANCES_INITIAL_LOAD};
  retrieve_instances_->LoadProjectsAndInstances(remembered_project, GetSelectedInstanceListScope())
      .Then(main_thread_executor_.get(),
            // The metric gets its own future continuation, so the time measured is only the
            // time that the call took.
            [metric = std::move(metric)](auto loading_result) mutable {
              if (loading_result.has_error()) metric.SetStatusCode(OrbitLogEvent::INTERNAL_ERROR);
              return loading_result;
            })
      .Then(main_thread_executor_.get(),
            [this](ErrorMessageOr<LoadProjectsAndInstancesResult> loading_result) {
              // `this` still exists when this lambda is executed. This is enforced, because
              // main_thread_executor_ is a member of `this`. When `this` is destroyed,
              // main_thread_executor_ is destroyed and the lambda is not executed. Check
              // Future::Then for details about the lambda not being executed.

              if (loading_result.has_error()) {
                emit InitialLoadingFailed();
                OnInstancesLoadingReturned(loading_result.error());
                return;
              }

              OnInitialLoadingReturnedSuccess(loading_result.value());
            });
}

void RetrieveInstancesWidget::OnInitialLoadingReturnedSuccess(
    LoadProjectsAndInstancesResult initial_load_result) {
  ORBIT_CHECK(ui_->projectComboBox->count() == 0);

  // From here on the projectComboBox is filled. To not trigger currentIndexChanged signals, the
  // signals of projectComboBox are blocked until the end of this function.
  ui_->projectComboBox->blockSignals(true);

  QString default_project_text =
      QString("Default Project (%1)").arg(initial_load_result.default_project.display_name);
  ui_->projectComboBox->addItem(default_project_text);

  QVector<Project>& projects{initial_load_result.projects};
  std::sort(projects.begin(), projects.end(),
            [](const Project& p1, const Project& p2) { return p1.display_name < p2.display_name; });

  for (const Project& project : initial_load_result.projects) {
    QString text = project.display_name;
    if (project == initial_load_result.default_project) {
      text.append(" (default)");
    }
    ui_->projectComboBox->addItem(text, QVariant::fromValue(project));

    // initial_load_result.instances is the list for a specific project, which is
    // initial_load_result.project_of_instances. (This can be different than the remembered project
    // which was used in InitialLoad.) Since the initial_load_result.instances will be shown by
    // ConnectToStadiaWidget, the combobox should have the project selected that belongs to this
    // list. This selection is done here.
    if (project == initial_load_result.project_of_instances) {
      // last added item
      ui_->projectComboBox->setCurrentIndex(ui_->projectComboBox->count() - 1);
    }
  }

  ui_->projectComboBox->blockSignals(false);

  OnInstancesLoadingReturned(initial_load_result.instances);
}

void RetrieveInstancesWidget::OnInstancesLoadingReturned(
    const ErrorMessageOr<QVector<Instance>>& loading_result) {
  if (loading_result.has_error()) {
    ORBIT_ERROR("instance loading returned with error: %s", loading_result.error().message());
    QMessageBox::critical(this, QCoreApplication::applicationName(),
                          QString::fromStdString(loading_result.error().message()));
    emit LoadingFailed();
    return;
  }
  emit LoadingSuccessful(loading_result.value());
}

void RetrieveInstancesWidget::OnReloadButtonClicked() {
  // Initial loading failed
  if (ui_->projectComboBox->count() == 0) {
    InitialLoad(std::nullopt);
    return;
  }

  std::optional<Project> selected_project;
  if (ui_->projectComboBox->currentData().canConvert<Project>()) {
    selected_project = ui_->projectComboBox->currentData().value<Project>();
  }

  emit LoadingStarted();
  retrieve_instances_->LoadInstancesWithoutCache(selected_project, GetSelectedInstanceListScope())
      .Then(main_thread_executor_.get(),
            [this](const ErrorMessageOr<QVector<Instance>>& load_result) {
              // `this` still exists when this lambda is executed. This is enforced, because
              // main_thread_executor_ is a member of `this`. When `this` is destroyed,
              // main_thread_executor_ is destroyed and the lambda is not executed. Check
              // Future::Then for details about the lambda not being executed.
              OnInstancesLoadingReturned(load_result);
            });
}

std::optional<orbit_ggp::Project> RetrieveInstancesWidget::GetSelectedProject() const {
  std::optional<Project> project;
  if (ui_->projectComboBox->currentData().canConvert<Project>()) {
    project = ui_->projectComboBox->currentData().value<Project>();
  }
  return project;
}

void RetrieveInstancesWidget::OnProjectComboBoxCurrentIndexChanged() {
  std::optional<Project> selected_project = GetSelectedProject();

  if (metrics_uploader_ != nullptr) {
    metrics_uploader_->SendLogEvent(OrbitLogEvent::ORBIT_PROJECT_CHANGED);
  }

  emit LoadingStarted();
  retrieve_instances_->LoadInstances(selected_project, GetSelectedInstanceListScope())
      .Then(main_thread_executor_.get(),
            [this, selected_project](const ErrorMessageOr<QVector<Instance>>& load_result) {
              // `this` still exists when this lambda is executed. This is enforced, because
              // main_thread_executor_ is a member of `this`. When `this` is destroyed,
              // main_thread_executor_ is destroyed and the lambda is not executed. Check
              // Future::Then for details about the lambda not being executed.

              if (load_result.has_value()) {
                SaveProjectToPersistentStorage(selected_project);
              } else {
                std::optional<Project> previously_selected =
                    LoadLastSelectedProjectFromPersistentStorage();
                // The upcoming call to setCurrentIndex is not user action, but only resetting to
                // previous values. Hence the signals are temporarily blocked.
                ui_->projectComboBox->blockSignals(true);
                if (previously_selected == std::nullopt) {
                  // If previously_selected is nullopt, that means QSettings contained either the
                  // default project or nothing (in which case selecting the default project is also
                  // correct). The first entry of the combobox (index 0) is the default project.
                  ui_->projectComboBox->setCurrentIndex(0);
                } else {
                  int index = ui_->projectComboBox->findData(
                      QVariant::fromValue(previously_selected.value()));
                  ui_->projectComboBox->setCurrentIndex(index);
                }
                ui_->projectComboBox->blockSignals(false);
              }

              OnInstancesLoadingReturned(load_result);
            });
}

void RetrieveInstancesWidget::OnAllCheckboxClicked() {
  InstanceListScope selected_scope = GetSelectedInstanceListScope();

  emit LoadingStarted();
  retrieve_instances_->LoadInstances(GetSelectedProject(), selected_scope)
      .Then(main_thread_executor_.get(),
            [widget = QPointer<RetrieveInstancesWidget>(this),
             selected_scope](const ErrorMessageOr<QVector<Instance>>& load_result) {
              if (widget == nullptr) return;

              if (load_result.has_value()) {
                SaveInstancesScopeToPersistentStorage(selected_scope);
              } else {
                // reset to the value before (value saved in PersistenStorage)
                widget->ui_->allCheckBox->setChecked(LoadInstancesScopeFromPersistentStorage() ==
                                                     InstanceListScope::kAllReservedInstances);
              }

              widget->OnInstancesLoadingReturned(load_result);
            });
}

}  // namespace orbit_session_setup<commit_msg>Fix use of wrong vector in RetrieveInstancesWidget (#3942)<commit_after>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "SessionSetup/RetrieveInstancesWidget.h"

#include <QCoreApplication>
#include <QLineEdit>
#include <QMessageBox>
#include <QObject>
#include <QPointer>
#include <QPushButton>
#include <QSettings>
#include <QVariant>
#include <memory>
#include <optional>

#include "MetricsUploader/ScopedMetric.h"
#include "MetricsUploader/orbit_log_event.pb.h"
#include "OrbitBase/Result.h"
#include "OrbitGgp/Client.h"
#include "QtUtils/MainThreadExecutorImpl.h"
#include "SessionSetup/PersistentStorage.h"
#include "SessionSetup/RetrieveInstances.h"
#include "ui_RetrieveInstancesWidget.h"

namespace orbit_session_setup {

using orbit_ggp::Instance;
using orbit_ggp::Project;
using LoadProjectsAndInstancesResult = RetrieveInstances::LoadProjectsAndInstancesResult;
using InstanceListScope = orbit_ggp::Client::InstanceListScope;
using orbit_metrics_uploader::OrbitLogEvent;
using orbit_metrics_uploader::ScopedMetric;

RetrieveInstancesWidget::~RetrieveInstancesWidget() = default;

RetrieveInstancesWidget::RetrieveInstancesWidget(QWidget* parent)
    : QWidget(parent),
      ui_(std::make_unique<Ui::RetrieveInstancesWidget>()),
      main_thread_executor_(orbit_qt_utils::MainThreadExecutorImpl::Create()),
      s_idle_(&state_machine_),
      s_loading_(&state_machine_),
      s_initial_loading_failed_(&state_machine_) {
  ui_->setupUi(this);

  SetupStateMachine();

  QObject::connect(ui_->filterLineEdit, &QLineEdit::textChanged, this,
                   &RetrieveInstancesWidget::FilterTextChanged);
  QObject::connect(ui_->reloadButton, &QPushButton::clicked, this,
                   &RetrieveInstancesWidget::OnReloadButtonClicked);
  QObject::connect(ui_->projectComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
                   &RetrieveInstancesWidget::OnProjectComboBoxCurrentIndexChanged);
  QObject::connect(ui_->allCheckBox, &QCheckBox::clicked, this,
                   &RetrieveInstancesWidget::OnAllCheckboxClicked);
}

void RetrieveInstancesWidget::SetupStateMachine() {
  state_machine_.setGlobalRestorePolicy(QStateMachine::RestoreProperties);

  s_idle_.assignProperty(ui_->projectComboBox, "enabled", true);
  s_idle_.assignProperty(ui_->filterLineEdit, "enabled", true);
  s_idle_.assignProperty(ui_->allCheckBox, "enabled", true);
  s_idle_.assignProperty(ui_->reloadButton, "enabled", true);
  s_idle_.addTransition(this, &RetrieveInstancesWidget::LoadingStarted, &s_loading_);

  s_loading_.assignProperty(ui_->projectComboBox, "enabled", false);
  s_loading_.assignProperty(ui_->filterLineEdit, "enabled", false);
  s_loading_.assignProperty(ui_->allCheckBox, "enabled", false);
  s_loading_.assignProperty(ui_->reloadButton, "enabled", false);
  s_loading_.addTransition(this, &RetrieveInstancesWidget::LoadingSuccessful, &s_idle_);
  s_loading_.addTransition(this, &RetrieveInstancesWidget::LoadingFailed, &s_idle_);
  s_loading_.addTransition(this, &RetrieveInstancesWidget::InitialLoadingFailed,
                           &s_initial_loading_failed_);

  s_initial_loading_failed_.assignProperty(ui_->projectComboBox, "enabled", false);
  s_initial_loading_failed_.assignProperty(ui_->filterLineEdit, "enabled", false);
  s_initial_loading_failed_.assignProperty(ui_->allCheckBox, "enabled", false);
  s_initial_loading_failed_.assignProperty(ui_->reloadButton, "enabled", true);
  s_initial_loading_failed_.addTransition(this, &RetrieveInstancesWidget::LoadingStarted,
                                          &s_loading_);
}

void RetrieveInstancesWidget::Start() {
  ORBIT_CHECK(retrieve_instances_ != nullptr);
  state_machine_.setInitialState(&s_loading_);
  state_machine_.start();

  ui_->allCheckBox->setChecked(LoadInstancesScopeFromPersistentStorage() ==
                               InstanceListScope::kAllReservedInstances);

  InitialLoad(LoadLastSelectedProjectFromPersistentStorage());
}

InstanceListScope RetrieveInstancesWidget::GetSelectedInstanceListScope() const {
  return ui_->allCheckBox->isChecked() ? InstanceListScope::kAllReservedInstances
                                       : InstanceListScope::kOnlyOwnInstances;
}

void RetrieveInstancesWidget::InitialLoad(const std::optional<Project>& remembered_project) {
  ORBIT_CHECK(ui_->projectComboBox->count() == 0);
  emit LoadingStarted();
  ScopedMetric metric{metrics_uploader_, OrbitLogEvent::ORBIT_INSTANCES_INITIAL_LOAD};
  retrieve_instances_->LoadProjectsAndInstances(remembered_project, GetSelectedInstanceListScope())
      .Then(main_thread_executor_.get(),
            // The metric gets its own future continuation, so the time measured is only the
            // time that the call took.
            [metric = std::move(metric)](auto loading_result) mutable {
              if (loading_result.has_error()) metric.SetStatusCode(OrbitLogEvent::INTERNAL_ERROR);
              return loading_result;
            })
      .Then(main_thread_executor_.get(),
            [this](ErrorMessageOr<LoadProjectsAndInstancesResult> loading_result) {
              // `this` still exists when this lambda is executed. This is enforced, because
              // main_thread_executor_ is a member of `this`. When `this` is destroyed,
              // main_thread_executor_ is destroyed and the lambda is not executed. Check
              // Future::Then for details about the lambda not being executed.

              if (loading_result.has_error()) {
                emit InitialLoadingFailed();
                OnInstancesLoadingReturned(loading_result.error());
                return;
              }

              OnInitialLoadingReturnedSuccess(loading_result.value());
            });
}

void RetrieveInstancesWidget::OnInitialLoadingReturnedSuccess(
    LoadProjectsAndInstancesResult initial_load_result) {
  ORBIT_CHECK(ui_->projectComboBox->count() == 0);

  // From here on the projectComboBox is filled. To not trigger currentIndexChanged signals, the
  // signals of projectComboBox are blocked until the end of this function.
  ui_->projectComboBox->blockSignals(true);

  QString default_project_text =
      QString("Default Project (%1)").arg(initial_load_result.default_project.display_name);
  ui_->projectComboBox->addItem(default_project_text);

  QVector<Project>& projects{initial_load_result.projects};
  std::sort(projects.begin(), projects.end(),
            [](const Project& p1, const Project& p2) { return p1.display_name < p2.display_name; });

  for (const Project& project : projects) {
    QString text = project.display_name;
    if (project == initial_load_result.default_project) {
      text.append(" (default)");
    }
    ui_->projectComboBox->addItem(text, QVariant::fromValue(project));

    // initial_load_result.instances is the list for a specific project, which is
    // initial_load_result.project_of_instances. (This can be different than the remembered project
    // which was used in InitialLoad.) Since the initial_load_result.instances will be shown by
    // ConnectToStadiaWidget, the combobox should have the project selected that belongs to this
    // list. This selection is done here.
    if (project == initial_load_result.project_of_instances) {
      // last added item
      ui_->projectComboBox->setCurrentIndex(ui_->projectComboBox->count() - 1);
    }
  }

  ui_->projectComboBox->blockSignals(false);

  OnInstancesLoadingReturned(initial_load_result.instances);
}

void RetrieveInstancesWidget::OnInstancesLoadingReturned(
    const ErrorMessageOr<QVector<Instance>>& loading_result) {
  if (loading_result.has_error()) {
    ORBIT_ERROR("instance loading returned with error: %s", loading_result.error().message());
    QMessageBox::critical(this, QCoreApplication::applicationName(),
                          QString::fromStdString(loading_result.error().message()));
    emit LoadingFailed();
    return;
  }
  emit LoadingSuccessful(loading_result.value());
}

void RetrieveInstancesWidget::OnReloadButtonClicked() {
  // Initial loading failed
  if (ui_->projectComboBox->count() == 0) {
    InitialLoad(std::nullopt);
    return;
  }

  std::optional<Project> selected_project;
  if (ui_->projectComboBox->currentData().canConvert<Project>()) {
    selected_project = ui_->projectComboBox->currentData().value<Project>();
  }

  emit LoadingStarted();
  retrieve_instances_->LoadInstancesWithoutCache(selected_project, GetSelectedInstanceListScope())
      .Then(main_thread_executor_.get(),
            [this](const ErrorMessageOr<QVector<Instance>>& load_result) {
              // `this` still exists when this lambda is executed. This is enforced, because
              // main_thread_executor_ is a member of `this`. When `this` is destroyed,
              // main_thread_executor_ is destroyed and the lambda is not executed. Check
              // Future::Then for details about the lambda not being executed.
              OnInstancesLoadingReturned(load_result);
            });
}

std::optional<orbit_ggp::Project> RetrieveInstancesWidget::GetSelectedProject() const {
  std::optional<Project> project;
  if (ui_->projectComboBox->currentData().canConvert<Project>()) {
    project = ui_->projectComboBox->currentData().value<Project>();
  }
  return project;
}

void RetrieveInstancesWidget::OnProjectComboBoxCurrentIndexChanged() {
  std::optional<Project> selected_project = GetSelectedProject();

  if (metrics_uploader_ != nullptr) {
    metrics_uploader_->SendLogEvent(OrbitLogEvent::ORBIT_PROJECT_CHANGED);
  }

  emit LoadingStarted();
  retrieve_instances_->LoadInstances(selected_project, GetSelectedInstanceListScope())
      .Then(main_thread_executor_.get(),
            [this, selected_project](const ErrorMessageOr<QVector<Instance>>& load_result) {
              // `this` still exists when this lambda is executed. This is enforced, because
              // main_thread_executor_ is a member of `this`. When `this` is destroyed,
              // main_thread_executor_ is destroyed and the lambda is not executed. Check
              // Future::Then for details about the lambda not being executed.

              if (load_result.has_value()) {
                SaveProjectToPersistentStorage(selected_project);
              } else {
                std::optional<Project> previously_selected =
                    LoadLastSelectedProjectFromPersistentStorage();
                // The upcoming call to setCurrentIndex is not user action, but only resetting to
                // previous values. Hence the signals are temporarily blocked.
                ui_->projectComboBox->blockSignals(true);
                if (previously_selected == std::nullopt) {
                  // If previously_selected is nullopt, that means QSettings contained either the
                  // default project or nothing (in which case selecting the default project is also
                  // correct). The first entry of the combobox (index 0) is the default project.
                  ui_->projectComboBox->setCurrentIndex(0);
                } else {
                  int index = ui_->projectComboBox->findData(
                      QVariant::fromValue(previously_selected.value()));
                  ui_->projectComboBox->setCurrentIndex(index);
                }
                ui_->projectComboBox->blockSignals(false);
              }

              OnInstancesLoadingReturned(load_result);
            });
}

void RetrieveInstancesWidget::OnAllCheckboxClicked() {
  InstanceListScope selected_scope = GetSelectedInstanceListScope();

  emit LoadingStarted();
  retrieve_instances_->LoadInstances(GetSelectedProject(), selected_scope)
      .Then(main_thread_executor_.get(),
            [widget = QPointer<RetrieveInstancesWidget>(this),
             selected_scope](const ErrorMessageOr<QVector<Instance>>& load_result) {
              if (widget == nullptr) return;

              if (load_result.has_value()) {
                SaveInstancesScopeToPersistentStorage(selected_scope);
              } else {
                // reset to the value before (value saved in PersistenStorage)
                widget->ui_->allCheckBox->setChecked(LoadInstancesScopeFromPersistentStorage() ==
                                                     InstanceListScope::kAllReservedInstances);
              }

              widget->OnInstancesLoadingReturned(load_result);
            });
}

}  // namespace orbit_session_setup<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/mlir_gpu/experimental/conv_emitter/conv_emitter.h"

#include "llvm/Support/raw_ostream.h"
#include "mlir/IR/AffineExpr.h"  // TF:local_config_mlir
#include "mlir/IR/AffineMap.h"  // TF:local_config_mlir
#include "mlir/IR/Builders.h"  // TF:local_config_mlir
#include "mlir/IR/Function.h"  // TF:local_config_mlir
#include "mlir/IR/Location.h"  // TF:local_config_mlir
#include "mlir/IR/MLIRContext.h"  // TF:local_config_mlir
#include "mlir/IR/Module.h"  // TF:local_config_mlir
#include "mlir/IR/StandardTypes.h"  // TF:local_config_mlir
#include "tensorflow/compiler/xla/service/hlo_parser.h"
#include "tensorflow/compiler/xla/tests/filecheck.h"
#include "tensorflow/core/platform/test.h"

namespace xla {
namespace gpu_mlir {
namespace {

mlir::Type ShapeToMlirType(const xla::Shape& shape, mlir::Builder* builder) {
  CHECK(shape.IsArray());
  mlir::Type element_type = [&] {
    switch (shape.element_type()) {
      case xla::F16:
        return builder->getF16Type();
      case xla::F32:
        return builder->getF32Type();
      default:
        break;
    }
    CHECK(false);
  }();
  std::vector<int64_t> physical_layout;
  std::vector<mlir::AffineExpr> major_to_minor;
  for (int i = shape.layout().minor_to_major_size() - 1; i >= 0; i--) {
    major_to_minor.push_back(
        builder->getAffineDimExpr(shape.layout().minor_to_major(i)));
    physical_layout.push_back(
        shape.dimensions(shape.layout().minor_to_major(i)));
  }
  return builder->getMemRefType(
      physical_layout, element_type,
      {builder->getAffineMap(major_to_minor.size(), 0, major_to_minor)});
}

std::string CompileHloConvAndGetMlir(absl::string_view hlo_text) {
  xla::HloModuleConfig hlo_config;
  xla::HloModule hlo_module("Conv", hlo_config);
  TF_CHECK_OK(xla::ParseHloString(hlo_text, &hlo_module));
  xla::HloInstruction* conv =
      hlo_module.entry_computation()->root_instruction();

  mlir::MLIRContext context;
  mlir::Location location = mlir::UnknownLoc::get(&context);
  auto mlir_module = mlir::ModuleOp::create(location);
  mlir::OpBuilder builder(&context);

  xla::Shape input_shape = conv->operand(0)->shape();
  xla::Shape filter_shape = conv->operand(1)->shape();
  xla::Shape output_shape = conv->shape().tuple_shapes(0);

  auto function = mlir::FuncOp::create(
      location, "Conv",
      builder.getFunctionType({ShapeToMlirType(output_shape, &builder),
                               ShapeToMlirType(input_shape, &builder),
                               ShapeToMlirType(filter_shape, &builder)},
                              {builder.getNoneType()}));
  mlir_module.push_back(function);

  auto* entry_block = function.addEntryBlock();
  builder.setInsertionPointToStart(entry_block);

  TF_CHECK_OK(xla::mlir_gpu::EmitConvolutionForwardAsMlir(
      conv, entry_block->getArgument(1), entry_block->getArgument(2),
      entry_block->getArgument(0), builder));

  mlir_module.verify();

  std::string mlir_text;
  llvm::raw_string_ostream strstream(mlir_text);
  function.print(strstream);
  return mlir_text;
}

// TODO(timshen): integrate this with mlir_gpu's testing infrastructure.
TEST(ConvEmtiterTest, TestDefault) {
  std::string hlo_text = R"(HloModule TestModule
ENTRY %TestComputation {
  %param_0 = f16[128,4,224,224]{1,3,2,0} parameter(0)
  %param_1 = f16[7,7,64,4]{3,1,0,2} parameter(1)
  ROOT %custom-call.1 = (f16[128,64,112,112]{1,3,2,0}, u8[0]{0}) custom-call(%param_0, %param_1), window={size=7x7 stride=2x2 pad=3_3x3_3}, dim_labels=bf01_01oi->bf01, custom_call_target="__cudnn$convForward", backend_config="{conv_result_scale:1}"
})";

  std::string expected_mlir_pattern =
      R"(
CHECK: func @Conv(%arg0: memref<128x112x112x64xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, %arg1: memref<128x224x224x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, %arg2: memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d2, d0, d1, d3)>) -> none {
CHECK-NEXT:   %0 = memref_cast %arg2 : memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d2, d0, d1, d3)> to memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>
CHECK-NEXT:   "affine.for"() ( {
CHECK-NEXT:   ^bb0(%arg3: index):
CHECK-NEXT:     "affine.for"() ( {
CHECK-NEXT:     ^bb0(%arg4: index):
CHECK-NEXT:       "affine.for"() ( {
CHECK-NEXT:       ^bb0(%arg5: index):
CHECK-NEXT:         "affine.for"() ( {
CHECK-NEXT:         ^bb0(%arg6: index):
CHECK-NEXT:           %1 = alloc() : memref<32x16xf32>
CHECK-NEXT:           "affine.for"() ( {
CHECK-NEXT:           ^bb0(%arg7: index):
CHECK-NEXT:             "affine.for"() ( {
CHECK-NEXT:             ^bb0(%arg8: index):
CHECK-NEXT:               %cst = constant 0.000000e+00 : f32
CHECK-NEXT:               "affine.store"(%cst, %1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (f32, memref<32x16xf32>, index, index) -> ()
CHECK-NEXT:               "affine.terminator"() : () -> ()
CHECK-NEXT:             }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (16)} : () -> ()
CHECK-NEXT:             "affine.terminator"() : () -> ()
CHECK-NEXT:           }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (32)} : () -> ()
CHECK-NEXT:           "affine.for"() ( {
CHECK-NEXT:           ^bb0(%arg7: index):
CHECK-NEXT:             "affine.for"() ( {
CHECK-NEXT:             ^bb0(%arg8: index):
CHECK-NEXT:               "affine.for"() ( {
CHECK-NEXT:               ^bb0(%arg9: index):
CHECK-NEXT:                 "affine.for"() ( {
CHECK-NEXT:                 ^bb0(%arg10: index):
CHECK-NEXT:                   "affine.for"() ( {
CHECK-NEXT:                   ^bb0(%arg11: index):
CHECK-NEXT:                     "affine.for"() ( {
CHECK-NEXT:                     ^bb0(%arg12: index):
CHECK-NEXT:                       %2 = "affine.load"(%arg1, %arg3, %arg9, %arg5, %arg6, %arg10, %arg11, %arg12, %arg8) {map = (d0, d1, d2, d3, d4, d5, d6, d7) -> (d0, d1 * 4 + d6, d2 * 2 + d4 - 3, (d3 * 16 + d7) * 2 + d5 - 3)} : (memref<128x224x224x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, index, index, index, index, index, index, index, index) -> f16
CHECK-NEXT:                       %3 = "affine.load"(%0, %arg4, %arg9, %arg10, %arg11, %arg12, %arg7) {map = (d0, d1, d2, d3, d4, d5) -> (d0 * 32 + d5, d1 * 4 + d4, d2, d3)} : (memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, index, index, index, index, index, index) -> f16
CHECK-NEXT:                       %4 = "affine.load"(%1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (memref<32x16xf32>, index, index) -> f32
CHECK-NEXT:                       %5 = mulf %2, %3 : f16
CHECK-NEXT:                       %6 = "std.addf"(%4, %5) : (f32, f16) -> f32
CHECK-NEXT:                       "affine.store"(%6, %1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (f32, memref<32x16xf32>, index, index) -> ()
CHECK-NEXT:                       "affine.terminator"() : () -> ()
CHECK-NEXT:                     }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (4)} : () -> ()
CHECK-NEXT:                     "affine.terminator"() : () -> ()
CHECK-NEXT:                   }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (7)} : () -> ()
CHECK-NEXT:                   "affine.terminator"() : () -> ()
CHECK-NEXT:                 }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (7)} : () -> ()
CHECK-NEXT:                 "affine.terminator"() : () -> ()
CHECK-NEXT:               }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (1)} : () -> ()
CHECK-NEXT:               "affine.terminator"() : () -> ()
CHECK-NEXT:             }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (16)} : () -> ()
CHECK-NEXT:             "affine.terminator"() : () -> ()
CHECK-NEXT:           }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (32)} : () -> ()
CHECK-NEXT:           "affine.for"() ( {
CHECK-NEXT:           ^bb0(%arg7: index):
CHECK-NEXT:             "affine.for"() ( {
CHECK-NEXT:             ^bb0(%arg8: index):
CHECK-NEXT:               %2 = "affine.load"(%1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (memref<32x16xf32>, index, index) -> f32
CHECK-NEXT:               "affine.store"(%2, %arg0, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8) {map = (d0, d1, d2, d3, d4, d5) -> (d0, d1 * 32 + d4, d2, d3 * 16 + d5)} : (f32, memref<128x112x112x64xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, index, index, index, index, index, index) -> ()
CHECK-NEXT:               "affine.terminator"() : () -> ()
CHECK-NEXT:             }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (16)} : () -> ()
CHECK-NEXT:             "affine.terminator"() : () -> ()
CHECK-NEXT:           }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (32)} : () -> ()
CHECK-NEXT:           "affine.terminator"() : () -> ()
CHECK-NEXT:         }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (7)} : () -> ()
CHECK-NEXT:         "affine.terminator"() : () -> ()
CHECK-NEXT:       }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (112)} : () -> ()
CHECK-NEXT:       "affine.terminator"() : () -> ()
CHECK-NEXT:     }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (2)} : () -> ()
CHECK-NEXT:     "affine.terminator"() : () -> ()
CHECK-NEXT:   }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (128)} : () -> ()
CHECK-NEXT: }
)";

  EXPECT_TRUE(
      RunFileCheck(CompileHloConvAndGetMlir(hlo_text), expected_mlir_pattern)
          .ValueOrDie());
}

}  // namespace
}  // namespace gpu_mlir
}  // namespace xla
<commit_msg>[XLA/MLIR_GPU] Plug leak in ConvEmitterTest<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/mlir_gpu/experimental/conv_emitter/conv_emitter.h"

#include "llvm/Support/raw_ostream.h"
#include "mlir/IR/AffineExpr.h"  // TF:local_config_mlir
#include "mlir/IR/AffineMap.h"  // TF:local_config_mlir
#include "mlir/IR/Builders.h"  // TF:local_config_mlir
#include "mlir/IR/Function.h"  // TF:local_config_mlir
#include "mlir/IR/Location.h"  // TF:local_config_mlir
#include "mlir/IR/MLIRContext.h"  // TF:local_config_mlir
#include "mlir/IR/Module.h"  // TF:local_config_mlir
#include "mlir/IR/StandardTypes.h"  // TF:local_config_mlir
#include "tensorflow/compiler/xla/service/hlo_parser.h"
#include "tensorflow/compiler/xla/tests/filecheck.h"
#include "tensorflow/core/platform/test.h"

namespace xla {
namespace gpu_mlir {
namespace {

mlir::Type ShapeToMlirType(const xla::Shape& shape, mlir::Builder* builder) {
  CHECK(shape.IsArray());
  mlir::Type element_type = [&] {
    switch (shape.element_type()) {
      case xla::F16:
        return builder->getF16Type();
      case xla::F32:
        return builder->getF32Type();
      default:
        break;
    }
    CHECK(false);
  }();
  std::vector<int64_t> physical_layout;
  std::vector<mlir::AffineExpr> major_to_minor;
  for (int i = shape.layout().minor_to_major_size() - 1; i >= 0; i--) {
    major_to_minor.push_back(
        builder->getAffineDimExpr(shape.layout().minor_to_major(i)));
    physical_layout.push_back(
        shape.dimensions(shape.layout().minor_to_major(i)));
  }
  return builder->getMemRefType(
      physical_layout, element_type,
      {builder->getAffineMap(major_to_minor.size(), 0, major_to_minor)});
}

std::string CompileHloConvAndGetMlir(absl::string_view hlo_text) {
  xla::HloModuleConfig hlo_config;
  xla::HloModule hlo_module("Conv", hlo_config);
  TF_CHECK_OK(xla::ParseHloString(hlo_text, &hlo_module));
  xla::HloInstruction* conv =
      hlo_module.entry_computation()->root_instruction();

  mlir::MLIRContext context;
  mlir::Location location = mlir::UnknownLoc::get(&context);
  mlir::OwningModuleRef mlir_module(mlir::ModuleOp::create(location));
  mlir::OpBuilder builder(&context);

  xla::Shape input_shape = conv->operand(0)->shape();
  xla::Shape filter_shape = conv->operand(1)->shape();
  xla::Shape output_shape = conv->shape().tuple_shapes(0);

  auto function = mlir::FuncOp::create(
      location, "Conv",
      builder.getFunctionType({ShapeToMlirType(output_shape, &builder),
                               ShapeToMlirType(input_shape, &builder),
                               ShapeToMlirType(filter_shape, &builder)},
                              {builder.getNoneType()}));
  mlir_module->push_back(function);

  auto* entry_block = function.addEntryBlock();
  builder.setInsertionPointToStart(entry_block);

  TF_CHECK_OK(xla::mlir_gpu::EmitConvolutionForwardAsMlir(
      conv, entry_block->getArgument(1), entry_block->getArgument(2),
      entry_block->getArgument(0), builder));

  mlir_module->verify();

  std::string mlir_text;
  llvm::raw_string_ostream strstream(mlir_text);
  function.print(strstream);
  return mlir_text;
}

// TODO(timshen): integrate this with mlir_gpu's testing infrastructure.
TEST(ConvEmitterTest, TestDefault) {
  std::string hlo_text = R"(HloModule TestModule
ENTRY %TestComputation {
  %param_0 = f16[128,4,224,224]{1,3,2,0} parameter(0)
  %param_1 = f16[7,7,64,4]{3,1,0,2} parameter(1)
  ROOT %custom-call.1 = (f16[128,64,112,112]{1,3,2,0}, u8[0]{0}) custom-call(%param_0, %param_1), window={size=7x7 stride=2x2 pad=3_3x3_3}, dim_labels=bf01_01oi->bf01, custom_call_target="__cudnn$convForward", backend_config="{conv_result_scale:1}"
})";

  std::string expected_mlir_pattern =
      R"(
CHECK: func @Conv(%arg0: memref<128x112x112x64xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, %arg1: memref<128x224x224x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, %arg2: memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d2, d0, d1, d3)>) -> none {
CHECK-NEXT:   %0 = memref_cast %arg2 : memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d2, d0, d1, d3)> to memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>
CHECK-NEXT:   "affine.for"() ( {
CHECK-NEXT:   ^bb0(%arg3: index):
CHECK-NEXT:     "affine.for"() ( {
CHECK-NEXT:     ^bb0(%arg4: index):
CHECK-NEXT:       "affine.for"() ( {
CHECK-NEXT:       ^bb0(%arg5: index):
CHECK-NEXT:         "affine.for"() ( {
CHECK-NEXT:         ^bb0(%arg6: index):
CHECK-NEXT:           %1 = alloc() : memref<32x16xf32>
CHECK-NEXT:           "affine.for"() ( {
CHECK-NEXT:           ^bb0(%arg7: index):
CHECK-NEXT:             "affine.for"() ( {
CHECK-NEXT:             ^bb0(%arg8: index):
CHECK-NEXT:               %cst = constant 0.000000e+00 : f32
CHECK-NEXT:               "affine.store"(%cst, %1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (f32, memref<32x16xf32>, index, index) -> ()
CHECK-NEXT:               "affine.terminator"() : () -> ()
CHECK-NEXT:             }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (16)} : () -> ()
CHECK-NEXT:             "affine.terminator"() : () -> ()
CHECK-NEXT:           }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (32)} : () -> ()
CHECK-NEXT:           "affine.for"() ( {
CHECK-NEXT:           ^bb0(%arg7: index):
CHECK-NEXT:             "affine.for"() ( {
CHECK-NEXT:             ^bb0(%arg8: index):
CHECK-NEXT:               "affine.for"() ( {
CHECK-NEXT:               ^bb0(%arg9: index):
CHECK-NEXT:                 "affine.for"() ( {
CHECK-NEXT:                 ^bb0(%arg10: index):
CHECK-NEXT:                   "affine.for"() ( {
CHECK-NEXT:                   ^bb0(%arg11: index):
CHECK-NEXT:                     "affine.for"() ( {
CHECK-NEXT:                     ^bb0(%arg12: index):
CHECK-NEXT:                       %2 = "affine.load"(%arg1, %arg3, %arg9, %arg5, %arg6, %arg10, %arg11, %arg12, %arg8) {map = (d0, d1, d2, d3, d4, d5, d6, d7) -> (d0, d1 * 4 + d6, d2 * 2 + d4 - 3, (d3 * 16 + d7) * 2 + d5 - 3)} : (memref<128x224x224x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, index, index, index, index, index, index, index, index) -> f16
CHECK-NEXT:                       %3 = "affine.load"(%0, %arg4, %arg9, %arg10, %arg11, %arg12, %arg7) {map = (d0, d1, d2, d3, d4, d5) -> (d0 * 32 + d5, d1 * 4 + d4, d2, d3)} : (memref<64x7x7x4xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, index, index, index, index, index, index) -> f16
CHECK-NEXT:                       %4 = "affine.load"(%1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (memref<32x16xf32>, index, index) -> f32
CHECK-NEXT:                       %5 = mulf %2, %3 : f16
CHECK-NEXT:                       %6 = "std.addf"(%4, %5) : (f32, f16) -> f32
CHECK-NEXT:                       "affine.store"(%6, %1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (f32, memref<32x16xf32>, index, index) -> ()
CHECK-NEXT:                       "affine.terminator"() : () -> ()
CHECK-NEXT:                     }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (4)} : () -> ()
CHECK-NEXT:                     "affine.terminator"() : () -> ()
CHECK-NEXT:                   }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (7)} : () -> ()
CHECK-NEXT:                   "affine.terminator"() : () -> ()
CHECK-NEXT:                 }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (7)} : () -> ()
CHECK-NEXT:                 "affine.terminator"() : () -> ()
CHECK-NEXT:               }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (1)} : () -> ()
CHECK-NEXT:               "affine.terminator"() : () -> ()
CHECK-NEXT:             }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (16)} : () -> ()
CHECK-NEXT:             "affine.terminator"() : () -> ()
CHECK-NEXT:           }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (32)} : () -> ()
CHECK-NEXT:           "affine.for"() ( {
CHECK-NEXT:           ^bb0(%arg7: index):
CHECK-NEXT:             "affine.for"() ( {
CHECK-NEXT:             ^bb0(%arg8: index):
CHECK-NEXT:               %2 = "affine.load"(%1, %arg7, %arg8) {map = (d0, d1) -> (d0, d1)} : (memref<32x16xf32>, index, index) -> f32
CHECK-NEXT:               "affine.store"(%2, %arg0, %arg3, %arg4, %arg5, %arg6, %arg7, %arg8) {map = (d0, d1, d2, d3, d4, d5) -> (d0, d1 * 32 + d4, d2, d3 * 16 + d5)} : (f32, memref<128x112x112x64xf16, (d0, d1, d2, d3) -> (d0, d2, d3, d1)>, index, index, index, index, index, index) -> ()
CHECK-NEXT:               "affine.terminator"() : () -> ()
CHECK-NEXT:             }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (16)} : () -> ()
CHECK-NEXT:             "affine.terminator"() : () -> ()
CHECK-NEXT:           }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (32)} : () -> ()
CHECK-NEXT:           "affine.terminator"() : () -> ()
CHECK-NEXT:         }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (7)} : () -> ()
CHECK-NEXT:         "affine.terminator"() : () -> ()
CHECK-NEXT:       }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (112)} : () -> ()
CHECK-NEXT:       "affine.terminator"() : () -> ()
CHECK-NEXT:     }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (2)} : () -> ()
CHECK-NEXT:     "affine.terminator"() : () -> ()
CHECK-NEXT:   }) {lower_bound = () -> (0), step = 1 : index, upper_bound = () -> (128)} : () -> ()
CHECK-NEXT: }
)";

  EXPECT_TRUE(
      RunFileCheck(CompileHloConvAndGetMlir(hlo_text), expected_mlir_pattern)
          .ValueOrDie());
}

}  // namespace
}  // namespace gpu_mlir
}  // namespace xla
<|endoftext|>


<commit_before>// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>

int main() {
  const size_t kLog2Size = 40;
  const uintptr_t kLocation = 0x40ULL << kLog2Size;
  void *p = mmap(
      reinterpret_cast<void*>(kLocation),
      1ULL << kLog2Size,
      PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,
      -1, 0);
  fprintf(stderr, "DONE %p\n", p);
  return p == MAP_FAILED;
}

// CHECK: DONE
<commit_msg>tsan: fix test<commit_after>// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>

int main() {
  const size_t kLog2Size = 39;
  const uintptr_t kLocation = 0x40ULL << kLog2Size;
  void *p = mmap(
      reinterpret_cast<void*>(kLocation),
      1ULL << kLog2Size,
      PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,
      -1, 0);
  fprintf(stderr, "DONE %p %d\n", p, errno);
  return p == MAP_FAILED;
}

// CHECK: DONE
<|endoftext|>


<commit_before>#include "ComplexSymLoader.h"
#include "FilepathHelper.h"
#include "SpriteFactory.h"
#include "SprTransLoader.h"

#include <sprite2/ComplexSymbol.h>
#include <simp/NodeComplex.h>

#include <fstream>

namespace gum
{

ComplexSymLoader::ComplexSymLoader(s2::ComplexSymbol* sym)
	: m_sym(sym)
{
	if (m_sym) {
		m_sym->AddReference();
	}
}

ComplexSymLoader::~ComplexSymLoader()
{
	if (m_sym) {
		m_sym->RemoveReference();
	}
}

void ComplexSymLoader::LoadJson(const std::string& filepath)
{
	if (!m_sym) {
		return;
	}

	Json::Value value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, value);
	fin.close();

	sm::rect scissor;
	scissor.xmin = static_cast<float>(value["xmin"].asInt());
	scissor.xmax = static_cast<float>(value["xmax"].asInt());
	scissor.ymin = static_cast<float>(value["ymin"].asInt());
	scissor.ymax = static_cast<float>(value["ymax"].asInt());
	m_sym->SetScissor(scissor);

	std::string dir = FilepathHelper::Dir(filepath);

	m_sym->Clear();
	for (int i = 0, n = value["sprite"].size(); i < n; ++i) {
		s2::Sprite* spr = SpriteFactory::Instance()->Create(value["sprite"][i], dir);
		m_sym->Add(spr);
	}

	LoadJsonAction(value, m_sym);
}

void ComplexSymLoader::LoadBin(const simp::NodeComplex* node)
{
	sm::rect scissor;
	scissor.xmin = node->scissor[0];
	scissor.ymin = node->scissor[1];
	scissor.xmax = node->scissor[2];
	scissor.ymax = node->scissor[3];
	m_sym->SetScissor(scissor);

	m_sym->Clear();
	for (int i = 0; i < node->sprs_n; ++i) {
		s2::Sprite* spr = SpriteFactory::Instance()->Create(node->sprs[i]);
		SprTransLoader::Load(spr, node->trans[i]);
		m_sym->Add(spr);
	}

	const std::vector<s2::Sprite*>& children = m_sym->GetChildren();
	std::vector<s2::ComplexSymbol::Action> dst;
	dst.reserve(node->actions_n);
	for (int i = 0; i < node->actions_n; ++i) {
		const simp::NodeComplex::Action& src_action = node->actions[i];
		s2::ComplexSymbol::Action dst_action;
		dst_action.name = src_action.name;
		dst_action.sprs.reserve(src_action.n);
		for (int j = 0; j < src_action.n; ++j) {
			dst_action.sprs.push_back(children[src_action.idx[j]]);
		}
		dst.push_back(dst_action);
	}
	m_sym->SetActions(dst);
}

void ComplexSymLoader::LoadJsonAction(const Json::Value& val, s2::ComplexSymbol* sym)
{
	const std::vector<s2::Sprite*>& children = sym->GetChildren();

	std::vector<Action> src;
	LoadJsonAction(val, src);
	std::vector<s2::ComplexSymbol::Action> dst;
	dst.reserve(src.size());
	for (int i = 0, n = src.size(); i < n; ++i) {
		const Action& src_action = src[i];
		s2::ComplexSymbol::Action dst_action;
		dst_action.name = src_action.name;
		dst_action.sprs.reserve(src_action.idx.size());
		for (int j = 0, m = src_action.idx.size(); j < m; ++j) {
			int idx = src_action.idx[j];
			if (idx >= 0) {
				dst_action.sprs.push_back(children[idx]);
			}
		}
		dst.push_back(dst_action);
	}
	sym->SetActions(dst);
}

void ComplexSymLoader::LoadJsonAction(const Json::Value& val, std::vector<Action>& actions)
{
	if (!val.isMember("action")) {
		return;
	}

	const Json::Value& actions_val = val["action"];
	for (int i = 0, n = actions_val.size(); i < n; ++i) {
		const Json::Value& src = actions_val[i];
		Action dst;
		dst.name = src["name"].asString();
		dst.idx.reserve(src["sprite"].size());
		for (int j = 0, m = src["sprite"].size(); j < m; ++j) {
			dst.idx.push_back(src["sprite"][j].asInt());
		}
		actions.push_back(dst);
	}
}

}<commit_msg>[FIXED] complex load<commit_after>#include "ComplexSymLoader.h"
#include "FilepathHelper.h"
#include "SpriteFactory.h"
#include "SprTransLoader.h"

#include <sprite2/S2_Sprite.h>
#include <sprite2/ComplexSymbol.h>
#include <simp/NodeComplex.h>

#include <fstream>

namespace gum
{

ComplexSymLoader::ComplexSymLoader(s2::ComplexSymbol* sym)
	: m_sym(sym)
{
	if (m_sym) {
		m_sym->AddReference();
	}
}

ComplexSymLoader::~ComplexSymLoader()
{
	if (m_sym) {
		m_sym->RemoveReference();
	}
}

void ComplexSymLoader::LoadJson(const std::string& filepath)
{
	if (!m_sym) {
		return;
	}

	Json::Value value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, value);
	fin.close();

	sm::rect scissor;
	scissor.xmin = static_cast<float>(value["xmin"].asInt());
	scissor.xmax = static_cast<float>(value["xmax"].asInt());
	scissor.ymin = static_cast<float>(value["ymin"].asInt());
	scissor.ymax = static_cast<float>(value["ymax"].asInt());
	m_sym->SetScissor(scissor);

	std::string dir = FilepathHelper::Dir(filepath);

	m_sym->Clear();
	for (int i = 0, n = value["sprite"].size(); i < n; ++i) {
		s2::Sprite* spr = SpriteFactory::Instance()->Create(value["sprite"][i], dir);
		m_sym->Add(spr);
		spr->RemoveReference();
	}

	LoadJsonAction(value, m_sym);
}

void ComplexSymLoader::LoadBin(const simp::NodeComplex* node)
{
	sm::rect scissor;
	scissor.xmin = node->scissor[0];
	scissor.ymin = node->scissor[1];
	scissor.xmax = node->scissor[2];
	scissor.ymax = node->scissor[3];
	m_sym->SetScissor(scissor);

	m_sym->Clear();
	for (int i = 0; i < node->sprs_n; ++i) {
		s2::Sprite* spr = SpriteFactory::Instance()->Create(node->sprs[i]);
		SprTransLoader::Load(spr, node->trans[i]);
		m_sym->Add(spr);
		spr->RemoveReference();
	}

	const std::vector<s2::Sprite*>& children = m_sym->GetChildren();
	std::vector<s2::ComplexSymbol::Action> dst;
	dst.reserve(node->actions_n);
	for (int i = 0; i < node->actions_n; ++i) {
		const simp::NodeComplex::Action& src_action = node->actions[i];
		s2::ComplexSymbol::Action dst_action;
		dst_action.name = src_action.name;
		dst_action.sprs.reserve(src_action.n);
		for (int j = 0; j < src_action.n; ++j) {
			dst_action.sprs.push_back(children[src_action.idx[j]]);
		}
		dst.push_back(dst_action);
	}
	m_sym->SetActions(dst);
}

void ComplexSymLoader::LoadJsonAction(const Json::Value& val, s2::ComplexSymbol* sym)
{
	const std::vector<s2::Sprite*>& children = sym->GetChildren();

	std::vector<Action> src;
	LoadJsonAction(val, src);
	std::vector<s2::ComplexSymbol::Action> dst;
	dst.reserve(src.size());
	for (int i = 0, n = src.size(); i < n; ++i) {
		const Action& src_action = src[i];
		s2::ComplexSymbol::Action dst_action;
		dst_action.name = src_action.name;
		dst_action.sprs.reserve(src_action.idx.size());
		for (int j = 0, m = src_action.idx.size(); j < m; ++j) {
			int idx = src_action.idx[j];
			if (idx >= 0) {
				dst_action.sprs.push_back(children[idx]);
			}
		}
		dst.push_back(dst_action);
	}
	sym->SetActions(dst);
}

void ComplexSymLoader::LoadJsonAction(const Json::Value& val, std::vector<Action>& actions)
{
	if (!val.isMember("action")) {
		return;
	}

	const Json::Value& actions_val = val["action"];
	for (int i = 0, n = actions_val.size(); i < n; ++i) {
		const Json::Value& src = actions_val[i];
		Action dst;
		dst.name = src["name"].asString();
		dst.idx.reserve(src["sprite"].size());
		for (int j = 0, m = src["sprite"].size(); j < m; ++j) {
			dst.idx.push_back(src["sprite"][j].asInt());
		}
		actions.push_back(dst);
	}
}

}<|endoftext|>


<commit_before>#include <LinearizedTree.h>

#include <algorithm>

LinearizedTree::LinearizedTree()
: _tree(nullptr)
, _strategy(None)
, _nextIndex(0)
{
}

LinearizedTree::LinearizedTree(const Tree* tree, Algorithm strategy)
: _tree(tree)
, _strategy(strategy)
, _nodes(tree->size())
, _nextIndex(0)
{
	linearize();
}

const Tree* LinearizedTree::tree() const
{
	return _tree;
}

void LinearizedTree::setTree(const Tree* tree)
{
	if (_tree == tree) return;

	_tree = tree;
}

void LinearizedTree::setAlgorithm(Algorithm strategy)
{
	if (_strategy == strategy) return;

	_strategy = strategy;
}

unsigned LinearizedTree::size() const
{
	return _tree ? _tree->size() : 0;
}

int LinearizedTree::maxId() const
{
    return _tree ? _tree->maxId() : -1;
}

const Node* LinearizedTree::root() const
{
	return _tree ? _tree->root() : nullptr;
}

int LinearizedTree::indexOf(const Node* node) const
{
	if (!_indices.count(node))
	{
		return -1;
	}

	return _indices.at(node);
}

int LinearizedTree::indexOf(int id) const
{
    return indexOf(getNode(id));
}

const Node* LinearizedTree::at(int index) const
{
	return _nodes[index];
}

const Node* LinearizedTree::operator[](int index) const
{
	return _nodes[index];
}

const Node* LinearizedTree::getNode(int id) const
{
    return _tree->getNode(id);
}

const std::vector<std::pair<int, int>>& LinearizedTree::thresholds() const
{
    return _treeDepthTresholds;
}

void LinearizedTree::treeLayerRangesDo(std::function<void(int, int)> callback) const
{
    if (_strategy == BreadthFirst || _strategy == OptimizedBreadthFirst)
    {
        for (const std::pair<int, int>& pair : _treeDepthTresholds)
        {
            callback(pair.first, pair.second);
        }
    }
}

std::vector<const Node*>::const_iterator LinearizedTree::begin() const
{
	return _nodes.begin();
}

std::vector<const Node*>::const_iterator LinearizedTree::end() const
{
	return _nodes.end();
}

void LinearizedTree::linearize()
{
	clear();

	if (!_tree)
	{
		return;
	}

	switch (_strategy)
	{
	case DepthFirst:
		linearizeDepthFirst();
		break;
	case BreadthFirst:
		linearizeBreadthFirst();
		break;
    case OptimizedBreadthFirst:
        linearizeOptimizedBreadthFirst();
        break;
    }
}

void LinearizedTree::clear()
{
	_nextIndex = 0;
	_nodes.clear();
	_indices.clear();
    _treeDepthTresholds.clear();

	if (_tree)
	{
        _nodes.resize(_tree->size());
	}
}

void LinearizedTree::add(const Node* node)
{
	int index = _nextIndex++;

	_nodes[index] = node;
	_indices[node] = index;
}

void LinearizedTree::linearizeDepthFirst()
{
	_tree->nodesDo([this](const Node* node) { add(node); });
}

void LinearizedTree::linearizeBreadthFirst()
{
	_tree->nodesOrderedByDepthDo([this](const Node* node) {
		add(node);

        if (_treeDepthTresholds.size() < node->depth()+1)
		{
            _treeDepthTresholds.emplace_back(indexOf(node), indexOf(node));
		}
        else
        {
            _treeDepthTresholds.back().second = indexOf(node);
        }
    });
}

void LinearizedTree::linearizeOptimizedBreadthFirst()
{
    std::vector<const Node*> currentLevel;

    _tree->nodesOrderedByDepthDo([this, &currentLevel](const Node* node)
    {
        if (!currentLevel.empty() && node->depth() > currentLevel.back()->depth())
        {
            std::sort(currentLevel.begin(), currentLevel.end(), [](const Node* node1, const Node* node2) {
                return (node1->isLeaf() ? 0 : 1) < (node2->isLeaf() ? 0 : 1);
            });

            for (const Node* child : currentLevel)
            {
                add(child);
            }

            for (const Node* child : currentLevel)
            {
                if (child->isLeaf())
                {
                    continue;
                }

                _treeDepthTresholds.emplace_back(indexOf(child), indexOf(currentLevel.back()));
                break;
            }

            currentLevel.clear();
        }

        currentLevel.push_back(node);
    });

    // only add the remaining nodes because they are all leafs
    for (const Node* child : currentLevel)
    {
        add(child);
    }
}
<commit_msg>Fix segfault in LinearizedTree constructor<commit_after>#include <LinearizedTree.h>

#include <algorithm>

LinearizedTree::LinearizedTree()
: _tree(nullptr)
, _strategy(None)
, _nextIndex(0)
{
}

LinearizedTree::LinearizedTree(const Tree* tree, Algorithm strategy)
: _tree(tree)
, _strategy(strategy)
, _nodes(tree ? tree->size() : 0)
, _nextIndex(0)
{
	linearize();
}

const Tree* LinearizedTree::tree() const
{
	return _tree;
}

void LinearizedTree::setTree(const Tree* tree)
{
	if (_tree == tree) return;

	_tree = tree;
}

void LinearizedTree::setAlgorithm(Algorithm strategy)
{
	if (_strategy == strategy) return;

	_strategy = strategy;
}

unsigned LinearizedTree::size() const
{
	return _tree ? _tree->size() : 0;
}

int LinearizedTree::maxId() const
{
    return _tree ? _tree->maxId() : -1;
}

const Node* LinearizedTree::root() const
{
	return _tree ? _tree->root() : nullptr;
}

int LinearizedTree::indexOf(const Node* node) const
{
	if (!_indices.count(node))
	{
		return -1;
	}

	return _indices.at(node);
}

int LinearizedTree::indexOf(int id) const
{
    return indexOf(getNode(id));
}

const Node* LinearizedTree::at(int index) const
{
	return _nodes[index];
}

const Node* LinearizedTree::operator[](int index) const
{
	return _nodes[index];
}

const Node* LinearizedTree::getNode(int id) const
{
    return _tree->getNode(id);
}

const std::vector<std::pair<int, int>>& LinearizedTree::thresholds() const
{
    return _treeDepthTresholds;
}

void LinearizedTree::treeLayerRangesDo(std::function<void(int, int)> callback) const
{
    if (_strategy == BreadthFirst || _strategy == OptimizedBreadthFirst)
    {
        for (const std::pair<int, int>& pair : _treeDepthTresholds)
        {
            callback(pair.first, pair.second);
        }
    }
}

std::vector<const Node*>::const_iterator LinearizedTree::begin() const
{
	return _nodes.begin();
}

std::vector<const Node*>::const_iterator LinearizedTree::end() const
{
	return _nodes.end();
}

void LinearizedTree::linearize()
{
	clear();

	if (!_tree)
	{
		return;
	}

	switch (_strategy)
	{
	case DepthFirst:
		linearizeDepthFirst();
		break;
	case BreadthFirst:
		linearizeBreadthFirst();
		break;
    case OptimizedBreadthFirst:
        linearizeOptimizedBreadthFirst();
        break;
    }
}

void LinearizedTree::clear()
{
	_nextIndex = 0;
	_nodes.clear();
	_indices.clear();
    _treeDepthTresholds.clear();

	if (_tree)
	{
        _nodes.resize(_tree->size());
	}
}

void LinearizedTree::add(const Node* node)
{
	int index = _nextIndex++;

	_nodes[index] = node;
	_indices[node] = index;
}

void LinearizedTree::linearizeDepthFirst()
{
	_tree->nodesDo([this](const Node* node) { add(node); });
}

void LinearizedTree::linearizeBreadthFirst()
{
	_tree->nodesOrderedByDepthDo([this](const Node* node) {
		add(node);

        if (_treeDepthTresholds.size() < node->depth()+1)
		{
            _treeDepthTresholds.emplace_back(indexOf(node), indexOf(node));
		}
        else
        {
            _treeDepthTresholds.back().second = indexOf(node);
        }
    });
}

void LinearizedTree::linearizeOptimizedBreadthFirst()
{
    std::vector<const Node*> currentLevel;

    _tree->nodesOrderedByDepthDo([this, &currentLevel](const Node* node)
    {
        if (!currentLevel.empty() && node->depth() > currentLevel.back()->depth())
        {
            std::sort(currentLevel.begin(), currentLevel.end(), [](const Node* node1, const Node* node2) {
                return (node1->isLeaf() ? 0 : 1) < (node2->isLeaf() ? 0 : 1);
            });

            for (const Node* child : currentLevel)
            {
                add(child);
            }

            for (const Node* child : currentLevel)
            {
                if (child->isLeaf())
                {
                    continue;
                }

                _treeDepthTresholds.emplace_back(indexOf(child), indexOf(currentLevel.back()));
                break;
            }

            currentLevel.clear();
        }

        currentLevel.push_back(node);
    });

    // only add the remaining nodes because they are all leafs
    for (const Node* child : currentLevel)
    {
        add(child);
    }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2005 by Jorrit Tyberghein
	      (C) 2005 by Frank Richter

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csgeom/math.h"
#include "csutil/sysfunc.h"
#include "csutil/threadjobqueue.h"

namespace CS
{
namespace Threading
{

  ThreadedJobQueue::ThreadedJobQueue (size_t numWorkers, ThreadPriority priority)
    : scfImplementationType (this),
    numWorkerThreads (numWorkers),
    shutdownQueue (false), outstandingJobs (0)
  {
    allThreadState = new ThreadState*[numWorkers];

    // Start up the threads
    for (size_t i = 0; i < numWorkerThreads; ++i)
    {
      allThreadState[i] = new ThreadState (this);
      allThreadState[i]->threadObject->SetPriority(priority);
      allThreads.Add (allThreadState[i]->threadObject);
    }
    allThreads.StartAll ();
  }

  ThreadedJobQueue::~ThreadedJobQueue ()
  {
    {
      // Empty the queue for new jobs
      MutexScopedLock lock (jobMutex);
      jobQueue.DeleteAll ();
    }

    // Wait for all threads to finish their current job
    shutdownQueue = true;
    newJob.NotifyAll ();
    allThreads.WaitAll ();

    // Deallocate
    for (size_t i = 0; i < numWorkerThreads; ++i)
    {
      delete allThreadState[i];
    }
    delete allThreadState;
  }

  void ThreadedJobQueue::Enqueue (iJob* job)
  {
    if (!job)
      return;

    MutexScopedLock lock (jobMutex);
    jobQueue.Push (job);
    CS::Threading::AtomicOperations::Increment (&outstandingJobs);
    newJob.NotifyOne ();
  }

  void ThreadedJobQueue::PullAndRun (iJob* job)
  {
    bool jobUnqued = false;

    {
      MutexScopedLock lock (jobMutex);
      // Check if in queue
      jobUnqued = jobQueue.Delete (job);
    }

    if (jobUnqued)
    {
      job->Run ();
      CS::Threading::AtomicOperations::Decrement (&outstandingJobs);
      return;
    }

    // Now we have to check the active jobs, just wait until it is done
    {
      MutexScopedLock lock (threadStateMutex);

      bool isRunning = false;
      size_t index;

      for (size_t i = 0; i < numWorkerThreads; ++i)
      {
        if (allThreadState[i]->currentJob == job)
        {
          isRunning = true;
          index = i;
          break;
        }
      }

      if (isRunning)
      {
        while (allThreadState[index]->currentJob == job)
          allThreadState[index]->jobFinished.Wait (threadStateMutex);
      }

    }
  }

  void ThreadedJobQueue::Unqueue (iJob* job, bool waitIfCurrent)
  {
    {
      MutexScopedLock lock (jobMutex);
      // Check if in queue
      bool jobUnqued = jobQueue.Delete (job);

      if (jobUnqued)
        return;
    }

    {
      // Check the running threads
      MutexScopedLock lock (threadStateMutex);

      bool isRunning = false;
      size_t index;

      for (size_t i = 0; i < numWorkerThreads; ++i)
      {
        if (allThreadState[i]->currentJob == job)
        {
          isRunning = true;
          index = i;
          break;
        }
      }

      if (isRunning && waitIfCurrent)
      {
        while (allThreadState[index]->currentJob == job)
          allThreadState[index]->jobFinished.Wait (threadStateMutex);
      }

    }
  }

  void ThreadedJobQueue::Wait (iJob* job)
  {
    while (true)
    {
      {
	// Check the running threads
	MutexScopedLock lock (threadStateMutex);

	bool isRunning = false;
	size_t index;

	for (size_t i = 0; i < numWorkerThreads; ++i)
	{
	  if (allThreadState[i]->currentJob == job)
	  {
	    isRunning = true;
	    index = i;
	    break;
	  }
	}

	if (isRunning)
	{
	  /* The job is currently running, so wait until it finished */
	  while (allThreadState[index]->currentJob == job)
	    allThreadState[index]->jobFinished.Wait (threadStateMutex);
	  return;
	}
      }

      {
	MutexScopedLock lock (jobMutex);
	// Check if in queue
	bool jobUnqued = jobQueue.Contains (job);

	if (!jobUnqued)
	  // Not queued or running at all (any more)
	  return;
      }

      /* The job is somewhere in a queue.
       * Just wait for any job to finish and check everything again...
       */
      if (!IsFinished())
      {
	jobFinished.Wait (jobFinishedMutex);
      }
    }
  }

  bool ThreadedJobQueue::IsFinished ()
  {
    int32 c = CS::Threading::AtomicOperations::Read (&outstandingJobs);
    return c == 0;
  }

  ThreadedJobQueue::QueueRunnable::QueueRunnable (ThreadedJobQueue* queue,
    ThreadState* ts)
    : ownerQueue (queue), threadState (ts)
  {
  }

  void ThreadedJobQueue::QueueRunnable::Run ()
  {
    while (true)
    {
      // Get a job
      {
        MutexScopedLock lock (ownerQueue->jobMutex);
        while (ownerQueue->jobQueue.GetSize () == 0)
        {
          if (ownerQueue->shutdownQueue)
            return;
          ownerQueue->newJob.Wait (ownerQueue->jobMutex);
        }

        {
          MutexScopedLock lock2 (ownerQueue->threadStateMutex);
          threadState->currentJob = ownerQueue->jobQueue.PopTop ();
        }
      }

      // Execute it
      if (threadState->currentJob)
      {
        threadState->currentJob->Run ();
        CS::Threading::AtomicOperations::Decrement (&(ownerQueue->outstandingJobs));
      }

      // Clean up
      {
        MutexScopedLock lock (ownerQueue->threadStateMutex);
        threadState->currentJob = 0;
        threadState->jobFinished.NotifyAll ();
      }
      {
        ownerQueue->jobFinished.NotifyAll ();
      }
    }
  }

  int32 ThreadedJobQueue::GetQueueCount()
  {
    return CS::Threading::AtomicOperations::Read(&outstandingJobs);
  }

}
}
<commit_msg>Fixed a delete that should be a delete[].<commit_after>/*
    Copyright (C) 2005 by Jorrit Tyberghein
	      (C) 2005 by Frank Richter

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csgeom/math.h"
#include "csutil/sysfunc.h"
#include "csutil/threadjobqueue.h"

namespace CS
{
namespace Threading
{

  ThreadedJobQueue::ThreadedJobQueue (size_t numWorkers, ThreadPriority priority)
    : scfImplementationType (this),
    numWorkerThreads (numWorkers),
    shutdownQueue (false), outstandingJobs (0)
  {
    allThreadState = new ThreadState*[numWorkers];

    // Start up the threads
    for (size_t i = 0; i < numWorkerThreads; ++i)
    {
      allThreadState[i] = new ThreadState (this);
      allThreadState[i]->threadObject->SetPriority(priority);
      allThreads.Add (allThreadState[i]->threadObject);
    }
    allThreads.StartAll ();
  }

  ThreadedJobQueue::~ThreadedJobQueue ()
  {
    {
      // Empty the queue for new jobs
      MutexScopedLock lock (jobMutex);
      jobQueue.DeleteAll ();
    }

    // Wait for all threads to finish their current job
    shutdownQueue = true;
    newJob.NotifyAll ();
    allThreads.WaitAll ();

    // Deallocate
    for (size_t i = 0; i < numWorkerThreads; ++i)
    {
      delete allThreadState[i];
    }
    delete[] allThreadState;
  }

  void ThreadedJobQueue::Enqueue (iJob* job)
  {
    if (!job)
      return;

    MutexScopedLock lock (jobMutex);
    jobQueue.Push (job);
    CS::Threading::AtomicOperations::Increment (&outstandingJobs);
    newJob.NotifyOne ();
  }

  void ThreadedJobQueue::PullAndRun (iJob* job)
  {
    bool jobUnqued = false;

    {
      MutexScopedLock lock (jobMutex);
      // Check if in queue
      jobUnqued = jobQueue.Delete (job);
    }

    if (jobUnqued)
    {
      job->Run ();
      CS::Threading::AtomicOperations::Decrement (&outstandingJobs);
      return;
    }

    // Now we have to check the active jobs, just wait until it is done
    {
      MutexScopedLock lock (threadStateMutex);

      bool isRunning = false;
      size_t index;

      for (size_t i = 0; i < numWorkerThreads; ++i)
      {
        if (allThreadState[i]->currentJob == job)
        {
          isRunning = true;
          index = i;
          break;
        }
      }

      if (isRunning)
      {
        while (allThreadState[index]->currentJob == job)
          allThreadState[index]->jobFinished.Wait (threadStateMutex);
      }

    }
  }

  void ThreadedJobQueue::Unqueue (iJob* job, bool waitIfCurrent)
  {
    {
      MutexScopedLock lock (jobMutex);
      // Check if in queue
      bool jobUnqued = jobQueue.Delete (job);

      if (jobUnqued)
        return;
    }

    {
      // Check the running threads
      MutexScopedLock lock (threadStateMutex);

      bool isRunning = false;
      size_t index;

      for (size_t i = 0; i < numWorkerThreads; ++i)
      {
        if (allThreadState[i]->currentJob == job)
        {
          isRunning = true;
          index = i;
          break;
        }
      }

      if (isRunning && waitIfCurrent)
      {
        while (allThreadState[index]->currentJob == job)
          allThreadState[index]->jobFinished.Wait (threadStateMutex);
      }

    }
  }

  void ThreadedJobQueue::Wait (iJob* job)
  {
    while (true)
    {
      {
	// Check the running threads
	MutexScopedLock lock (threadStateMutex);

	bool isRunning = false;
	size_t index;

	for (size_t i = 0; i < numWorkerThreads; ++i)
	{
	  if (allThreadState[i]->currentJob == job)
	  {
	    isRunning = true;
	    index = i;
	    break;
	  }
	}

	if (isRunning)
	{
	  /* The job is currently running, so wait until it finished */
	  while (allThreadState[index]->currentJob == job)
	    allThreadState[index]->jobFinished.Wait (threadStateMutex);
	  return;
	}
      }

      {
	MutexScopedLock lock (jobMutex);
	// Check if in queue
	bool jobUnqued = jobQueue.Contains (job);

	if (!jobUnqued)
	  // Not queued or running at all (any more)
	  return;
      }

      /* The job is somewhere in a queue.
       * Just wait for any job to finish and check everything again...
       */
      if (!IsFinished())
      {
	jobFinished.Wait (jobFinishedMutex);
      }
    }
  }

  bool ThreadedJobQueue::IsFinished ()
  {
    int32 c = CS::Threading::AtomicOperations::Read (&outstandingJobs);
    return c == 0;
  }

  ThreadedJobQueue::QueueRunnable::QueueRunnable (ThreadedJobQueue* queue,
    ThreadState* ts)
    : ownerQueue (queue), threadState (ts)
  {
  }

  void ThreadedJobQueue::QueueRunnable::Run ()
  {
    while (true)
    {
      // Get a job
      {
        MutexScopedLock lock (ownerQueue->jobMutex);
        while (ownerQueue->jobQueue.GetSize () == 0)
        {
          if (ownerQueue->shutdownQueue)
            return;
          ownerQueue->newJob.Wait (ownerQueue->jobMutex);
        }

        {
          MutexScopedLock lock2 (ownerQueue->threadStateMutex);
          threadState->currentJob = ownerQueue->jobQueue.PopTop ();
        }
      }

      // Execute it
      if (threadState->currentJob)
      {
        threadState->currentJob->Run ();
        CS::Threading::AtomicOperations::Decrement (&(ownerQueue->outstandingJobs));
      }

      // Clean up
      {
        MutexScopedLock lock (ownerQueue->threadStateMutex);
        threadState->currentJob = 0;
        threadState->jobFinished.NotifyAll ();
      }
      {
        ownerQueue->jobFinished.NotifyAll ();
      }
    }
  }

  int32 ThreadedJobQueue::GetQueueCount()
  {
    return CS::Threading::AtomicOperations::Read(&outstandingJobs);
  }

}
}
<|endoftext|>