<commit_before>#include "WinConfiguration.h"
#include "Application.h"
#include "ModuleEditor.h"
#include "ModuleWindow.h"
#include "ModuleRenderer3D.h"

#include "Imgui/imgui.h"

WinConfiguration::WinConfiguration() : EditorWindow()
{
}

WinConfiguration::~WinConfiguration()
{
}

void WinConfiguration::Start()
{
	//FPS Graphs
	slider_fps = 60;
	fps.StartBar(1000);
	ms.StartBar(1);

	//Hardware specs
	if (SDL_Has3DNow()) caps += "3DNow, ";
	if (SDL_HasAltiVec()) caps += "AltiVec, ";
	if (SDL_HasAVX()) caps += "AVX, ";
	if (SDL_HasMMX()) caps += "MMX, ";
	if (SDL_HasRDTSC()) caps += "RDTSC, ";
	if (SDL_HasSSE()) caps += "SSE, ";
	if (SDL_HasSSE2()) caps += "SSE2, ";
	if (SDL_HasSSE3()) caps += "SSE3, ";
	if (SDL_HasSSE41()) caps += "SSE41, ";
	if (SDL_HasSSE42()) caps += "SSE42, ";

	//VRAM
	glGetIntegerv(GPU_TOTAL_AVAILABLE_MEM, &total_vram);
	glGetIntegerv(GPU_CURRENT_AVAILABLE_MEM, &available_vram);
	glGetIntegerv(GPU_USAGE_MEM, &usage_vram);
	total_vram /= 1000;
	available_vram /= 1000;
	usage_vram /= 1000;
}

void WinConfiguration::CleanUp()
{
}

void WinConfiguration::Update()
{
	fps.FillBar(App->GetFPS());
	ms.FillBar(App->GetMs());

	if (is_open)
	{
		ImGui::Begin("Configuration", &is_open);

		ImGui::PushItemWidth(-140);

		TabApplication();
		TabWindow();
		TabRenderer();
		TabHardware();

		ImGui::End();
	}
}

void WinConfiguration::TabApplication()
{
	if (ImGui::CollapsingHeader("Application"))
	{
		ImGui::Spacing();
		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "Personalization:");
		ImGui::Spacing();

		char tmp_str[100];
		//App name
		strcpy_s(tmp_str, sizeof(tmp_str), App->GetName().c_str());
		if (ImGui::InputText("Name", tmp_str, sizeof(tmp_str)))
		{
			App->SetName(tmp_str);
		}

		//Organization name
		strcpy_s(tmp_str, sizeof(tmp_str), App->GetOrganization().c_str());
		if (ImGui::InputText("Organization", tmp_str, sizeof(tmp_str)))
		{
			App->SetOrganization(tmp_str);
		}

		ImGui::Spacing();
		ImGui::Separator();
		ImGui::Spacing();

		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "Performance:");
		ImGui::Spacing();
		//Performance
		if (ImGui::SliderInt("Max FPS", &slider_fps, 0, 60, NULL))
			App->SetMaxFPS(slider_fps);

		char title[25];
		sprintf_s(title, 25, "Framerate %.1f", fps.GetData()[fps.GetData().size() - 1]);
		ImGui::PlotHistogram("##framerate", &fps.GetData()[0], fps.GetData().size(), 0, title, 0.0f, 100.0f, ImVec2(310, 100));

		sprintf_s(title, 25, "Milliseconds %.1f", ms.GetData()[ms.GetData().size() - 1]);
		ImGui::PlotHistogram("##framerate", &ms.GetData()[0], ms.GetData().size(), 0, title, 0.0f, 40.0f, ImVec2(310, 100));

		//sprintf_s(tmp_str, sizeof(tmp_str), "Framerate %.1f")
	}
}

void WinConfiguration::TabWindow()
{
	if (ImGui::CollapsingHeader("Window"))
	{
		bool bool_tmp;
		int  int_tmp;

		int_tmp = App->window->GetWidth();
		if (ImGui::SliderInt("Width", &int_tmp, 0, 2000))
		{
			App->window->SetWidth(int_tmp);
		}

		int_tmp = App->window->GetHeight();
		if (ImGui::SliderInt("Height", &int_tmp, 0, 2000))
		{
			App->window->SetHeight(int_tmp);
		}

		bool_tmp = App->window->IsFullscreen();
		if (ImGui::Checkbox("Fullscreen", &bool_tmp))
		{
			App->window->SetFullscreen(bool_tmp);
		}

		ImGui::SameLine();

		bool_tmp = App->window->IsResizable();
		if (ImGui::Checkbox("Resizable", &bool_tmp))
		{
			App->window->SetResizable(bool_tmp);
		}

		bool_tmp = App->window->IsBorderless();
		if (ImGui::Checkbox("Borderless", &bool_tmp))
		{
			App->window->SetBorderless(bool_tmp);
		}

		ImGui::SameLine();

		bool_tmp = App->window->IsFullScreenDesktop();
		if (ImGui::Checkbox("Fullscreen desktop", &bool_tmp))
		{
			App->window->SetFullScreenDesktop(bool_tmp);
		}
	}
}

void WinConfiguration::TabRenderer()
{
	if (ImGui::CollapsingHeader("Renderer"))
	{
		bool bool_tmp;

		bool_tmp = App->renderer3D->draw_normals;
		if (ImGui::Checkbox("Draw Normals", &bool_tmp))
		{
			App->renderer3D->draw_normals = bool_tmp;
		}

		bool_tmp = App->renderer3D->draw_wireframe;
		if (ImGui::Checkbox("Draw wireframe", &bool_tmp))
		{
			App->renderer3D->draw_wireframe = bool_tmp;
		}

		bool_tmp = App->renderer3D->draw_textures;
		if (ImGui::Checkbox("Draw textures", &bool_tmp))
		{
			App->renderer3D->EnableTextures(bool_tmp);
		}

		bool_tmp = App->renderer3D->draw_meshes;
		if (ImGui::Checkbox("Draw mesh", &bool_tmp))
		{
			App->renderer3D->draw_meshes = bool_tmp;
		}
	}
}

void WinConfiguration::TabHardware()
{
	if (ImGui::CollapsingHeader("Hardware"))
	{
		//CPU
		ImGui::Spacing();
		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "CPU:");
		ImGui::Spacing();
		ImGui::TextWrapped("CPUs: %i Cores", SDL_GetCPUCount());
		ImGui::TextWrapped("Memory Ram: %i GB", (SDL_GetSystemRAM() / 1000));
		ImGui::TextWrapped("CPU Cache: %i bits", SDL_GetCPUCacheLineSize());
		ImGui::TextWrapped("Caps: %s", caps.c_str());

		ImGui::Spacing();
		ImGui::Separator();
		ImGui::Spacing();

		//GPU
		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "GPU:");
		ImGui::Spacing();
		ImGui::TextWrapped("Brand: %s", glGetString(GL_VENDOR));
		ImGui::TextWrapped("GPU: %s", glGetString(GL_RENDERER));
		ImGui::TextWrapped("GL Version: %s", glGetString(GL_VERSION));
		ImGui::TextWrapped("GLSL Version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));

		//VRAM
		ImGui::TextWrapped("VRAM Budget: %i MB", total_vram);
		ImGui::TextWrapped("VRAM Avaliable: %i MB", available_vram);
		ImGui::TextWrapped("VRAM Usage: %i MB", usage_vram);
	}
}<commit_msg>Render configuration window structure<commit_after>#include "WinConfiguration.h"
#include "Application.h"
#include "ModuleEditor.h"
#include "ModuleWindow.h"
#include "ModuleRenderer3D.h"

#include "Imgui/imgui.h"

WinConfiguration::WinConfiguration() : EditorWindow()
{
}

WinConfiguration::~WinConfiguration()
{
}

void WinConfiguration::Start()
{
	//FPS Graphs
	slider_fps = 60;
	fps.StartBar(1000);
	ms.StartBar(1);

	//Hardware specs
	if (SDL_Has3DNow()) caps += "3DNow, ";
	if (SDL_HasAltiVec()) caps += "AltiVec, ";
	if (SDL_HasAVX()) caps += "AVX, ";
	if (SDL_HasMMX()) caps += "MMX, ";
	if (SDL_HasRDTSC()) caps += "RDTSC, ";
	if (SDL_HasSSE()) caps += "SSE, ";
	if (SDL_HasSSE2()) caps += "SSE2, ";
	if (SDL_HasSSE3()) caps += "SSE3, ";
	if (SDL_HasSSE41()) caps += "SSE41, ";
	if (SDL_HasSSE42()) caps += "SSE42, ";

	//VRAM
	glGetIntegerv(GPU_TOTAL_AVAILABLE_MEM, &total_vram);
	glGetIntegerv(GPU_CURRENT_AVAILABLE_MEM, &available_vram);
	glGetIntegerv(GPU_USAGE_MEM, &usage_vram);
	total_vram /= 1000;
	available_vram /= 1000;
	usage_vram /= 1000;
}

void WinConfiguration::CleanUp()
{
}

void WinConfiguration::Update()
{
	fps.FillBar(App->GetFPS());
	ms.FillBar(App->GetMs());

	if (is_open)
	{
		ImGui::Begin("Configuration", &is_open);

		ImGui::PushItemWidth(-140);

		TabApplication();
		TabWindow();
		TabRenderer();
		TabHardware();

		ImGui::End();
	}
}

void WinConfiguration::TabApplication()
{
	if (ImGui::CollapsingHeader("Application"))
	{
		ImGui::Spacing();
		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "Personalization:");
		ImGui::Spacing();

		char tmp_str[100];
		//App name
		strcpy_s(tmp_str, sizeof(tmp_str), App->GetName().c_str());
		if (ImGui::InputText("Name", tmp_str, sizeof(tmp_str)))
		{
			App->SetName(tmp_str);
		}

		//Organization name
		strcpy_s(tmp_str, sizeof(tmp_str), App->GetOrganization().c_str());
		if (ImGui::InputText("Organization", tmp_str, sizeof(tmp_str)))
		{
			App->SetOrganization(tmp_str);
		}

		ImGui::Spacing();
		ImGui::Separator();
		ImGui::Spacing();

		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "Performance:");
		ImGui::Spacing();
		//Performance
		if (ImGui::SliderInt("Max FPS", &slider_fps, 0, 60, NULL))
			App->SetMaxFPS(slider_fps);

		char title[25];
		sprintf_s(title, 25, "Framerate %.1f", fps.GetData()[fps.GetData().size() - 1]);
		ImGui::PlotHistogram("##framerate", &fps.GetData()[0], fps.GetData().size(), 0, title, 0.0f, 100.0f, ImVec2(310, 100));

		sprintf_s(title, 25, "Milliseconds %.1f", ms.GetData()[ms.GetData().size() - 1]);
		ImGui::PlotHistogram("##framerate", &ms.GetData()[0], ms.GetData().size(), 0, title, 0.0f, 40.0f, ImVec2(310, 100));

		//sprintf_s(tmp_str, sizeof(tmp_str), "Framerate %.1f")
	}
}

void WinConfiguration::TabWindow()
{
	if (ImGui::CollapsingHeader("Window"))
	{
		bool bool_tmp;
		int  int_tmp;

		int_tmp = App->window->GetWidth();
		if (ImGui::SliderInt("Width", &int_tmp, 0, 2000))
		{
			App->window->SetWidth(int_tmp);
		}

		int_tmp = App->window->GetHeight();
		if (ImGui::SliderInt("Height", &int_tmp, 0, 2000))
		{
			App->window->SetHeight(int_tmp);
		}

		bool_tmp = App->window->IsFullscreen();
		if (ImGui::Checkbox("Fullscreen", &bool_tmp))
		{
			App->window->SetFullscreen(bool_tmp);
		}

		ImGui::SameLine();

		bool_tmp = App->window->IsResizable();
		if (ImGui::Checkbox("Resizable", &bool_tmp))
		{
			App->window->SetResizable(bool_tmp);
		}

		bool_tmp = App->window->IsBorderless();
		if (ImGui::Checkbox("Borderless", &bool_tmp))
		{
			App->window->SetBorderless(bool_tmp);
		}

		ImGui::SameLine();

		bool_tmp = App->window->IsFullScreenDesktop();
		if (ImGui::Checkbox("Fullscreen desktop", &bool_tmp))
		{
			App->window->SetFullScreenDesktop(bool_tmp);
		}
	}
}

void WinConfiguration::TabRenderer()
{
	if (ImGui::CollapsingHeader("Render"))
	{
		bool bool_tmp;

		if (ImGui::TreeNodeEx("Geometry"))
		{
			bool_tmp = App->renderer3D->draw_normals;
			if (ImGui::Checkbox("Draw Normals", &bool_tmp))
			{
				App->renderer3D->draw_normals = bool_tmp;
			}

			bool_tmp = App->renderer3D->draw_wireframe;
			if (ImGui::Checkbox("Draw wireframe", &bool_tmp))
			{
				App->renderer3D->draw_wireframe = bool_tmp;
			}

			bool_tmp = App->renderer3D->draw_meshes;
			if (ImGui::Checkbox("Draw mesh", &bool_tmp))
			{
				App->renderer3D->draw_meshes = bool_tmp;
			}

			ImGui::TreePop();
		}

		if (ImGui::TreeNodeEx("Textures"))
		{
			bool_tmp = App->renderer3D->draw_textures;
			if (ImGui::Checkbox("Draw textures", &bool_tmp))
			{
				App->renderer3D->EnableTextures(bool_tmp);
			}

			ImGui::TreePop();
		}

		if (ImGui::TreeNodeEx("Lights"))
		{

			ImGui::TreePop();
		}
	}
}

void WinConfiguration::TabHardware()
{
	if (ImGui::CollapsingHeader("Hardware"))
	{
		//CPU
		ImGui::Spacing();
		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "CPU:");
		ImGui::Spacing();
		ImGui::TextWrapped("CPUs: %i Cores", SDL_GetCPUCount());
		ImGui::TextWrapped("Memory Ram: %i GB", (SDL_GetSystemRAM() / 1000));
		ImGui::TextWrapped("CPU Cache: %i bits", SDL_GetCPUCacheLineSize());
		ImGui::TextWrapped("Caps: %s", caps.c_str());

		ImGui::Spacing();
		ImGui::Separator();
		ImGui::Spacing();

		//GPU
		ImGui::TextColored(ImVec4(0.0f, 1.0f, 1.0f, 1.0f), "GPU:");
		ImGui::Spacing();
		ImGui::TextWrapped("Brand: %s", glGetString(GL_VENDOR));
		ImGui::TextWrapped("GPU: %s", glGetString(GL_RENDERER));
		ImGui::TextWrapped("GL Version: %s", glGetString(GL_VERSION));
		ImGui::TextWrapped("GLSL Version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));

		//VRAM
		ImGui::TextWrapped("VRAM Budget: %i MB", total_vram);
		ImGui::TextWrapped("VRAM Avaliable: %i MB", available_vram);
		ImGui::TextWrapped("VRAM Usage: %i MB", usage_vram);
	}
}<|endoftext|>


<commit_before>// Fill out your copyright notice in the Description page of Project Settings.

#include "PongGame.h"
#include "Relay.h"

#include <iostream>
#include <array>
#include <asio.hpp>
#include <unistd.h>
#include <exception>

using asio::ip::tcp;

FRelay::FRelay()
{
    //host = "localhost";
    port = 6000;
    connected = false;
    serverCreated = false;
}

FRelay::~FRelay()
{
}

void Server::create(int port) {
    tcp_server.reset();
    io_service.reset();

    io_service = std::make_unique<asio::io_service>();
    tcp_server = std::make_unique<TcpServer>(*io_service, port);
}

void FRelay::TryConnect()
{
    server.io_service->poll();
}

std::array<char, 4> int_to_buf(int v) {
    std::array<char, 4> buf;
    int base = 1 << 8;
    for (int i = 0; i < 4; ++i) {
        buf[i] = v % base;
        v /= base;
    }
    return buf;
}

ActionType FRelay::Act(char* ptr, size_t size)
{
    if (!serverCreated) {
        // We can't do this in constructor because it's evaluated even before
        // the start of the game.
        server.create(port);
        serverCreated = true;
        server.tcp_server->start_accept();
    }

    if (!connected) {
        TryConnect();
        if (!server.tcp_server->connected) {
            throw std::logic_error("No clients accepted.");
        }
        connected = true;
    }

    auto& socket = server.tcp_server->current_connection_->socket_;

    //UE_LOG(LogTemp, Warning, TEXT("Sending %d bytes..."), size);

    try {
        asio::error_code error;
        auto len_buf = int_to_buf(size);
        size_t out_len = socket.write_some(asio::buffer(len_buf), error);
        if (out_len != 4 || error) {
            throw asio::system_error(error);
        }

        //size_t out_len = socket.write_some(asio::buffer(size), error);
        out_len = socket.write_some(asio::buffer(ptr, size), error);
        //UE_LOG(LogTemp, Warning, TEXT("Sent %d bytes"), out_len);

        if (error) {
            throw asio::system_error(error);
        }

        std::array<uint8_t, ACTION_SIZE> buf;
        int retries = 5;
        while (true) {
            size_t in_len = asio::read(*socket, asio::buffer(buf), asio::transfer_exactly(ACTION_SIZE), error);
            //UE_LOG(LogTemp, Warning, TEXT("Read %d bytes"), in_len);

            if (in_len == ACTION_SIZE) {
                break;
            }
            if (in_len != 0) {
                throw std::logic_error("Wrong length " + std::to_string(in_len));
            }

            if (error == asio::error::eof) {
                if (!(--retries)) {
                    throw std::logic_error("Timeout");
                    break;
                }
                UE_LOG(LogTemp, Warning, TEXT("EOF, retrying: %d"), retries);
                sleep(1);
                continue;
            } else if (error) {
                throw asio::system_error(error);
            }
        }
        return buf;

    } catch (std::exception& e) {
        connected = false;
        FString error_message(e.what());
        UE_LOG(LogTemp, Warning, TEXT("Caught an exception: %s"), *error_message);

        throw e;
    }
}
<commit_msg>Reset after polling. Start accepting new connections on disconnect<commit_after>// Fill out your copyright notice in the Description page of Project Settings.

#include "PongGame.h"
#include "Relay.h"

#include <iostream>
#include <array>
#include <asio.hpp>
#include <unistd.h>
#include <exception>

using asio::ip::tcp;

FRelay::FRelay()
{
    //host = "localhost";
    port = 6000;
    connected = false;
    serverCreated = false;
}

FRelay::~FRelay()
{
}

void Server::create(int port) {
    tcp_server.reset();
    io_service.reset();

    io_service = std::make_unique<asio::io_service>();
    tcp_server = std::make_unique<TcpServer>(*io_service, port);
}

void FRelay::TryConnect()
{
    server.io_service->poll();
    server.io_service->reset();
}

std::array<char, 4> int_to_buf(int v) {
    std::array<char, 4> buf;
    int base = 1 << 8;
    for (int i = 0; i < 4; ++i) {
        buf[i] = v % base;
        v /= base;
    }
    return buf;
}

ActionType FRelay::Act(char* ptr, size_t size)
{
    if (!serverCreated) {
        // We can't do this in constructor because it's evaluated even before
        // the start of the game.
        server.create(port);
        serverCreated = true;
        server.tcp_server->start_accept();
    }

    if (!connected) {
        TryConnect();
        if (!server.tcp_server->connected) {
            throw std::logic_error("No clients accepted.");
        }
        connected = true;
    }

    auto& socket = server.tcp_server->current_connection_->socket();

    //UE_LOG(LogTemp, Warning, TEXT("Sending %d bytes..."), size);

    try {
        asio::error_code error;
        auto len_buf = int_to_buf(size);
        size_t out_len = socket.write_some(asio::buffer(len_buf), error);
        if (out_len != 4 || error) {
            throw asio::system_error(error);
        }

        //size_t out_len = socket.write_some(asio::buffer(size), error);
        out_len = socket.write_some(asio::buffer(ptr, size), error);
        //UE_LOG(LogTemp, Warning, TEXT("Sent %d bytes"), out_len);

        if (error) {
            throw asio::system_error(error);
        }

        std::array<uint8_t, ACTION_SIZE> buf;
        int retries = 5;
        while (true) {
            size_t in_len = asio::read(*socket, asio::buffer(buf), asio::transfer_exactly(ACTION_SIZE), error);
            //UE_LOG(LogTemp, Warning, TEXT("Read %d bytes"), in_len);

            if (in_len == ACTION_SIZE) {
                break;
            }
            if (in_len != 0) {
                throw std::logic_error("Wrong length " + std::to_string(in_len));
            }

            if (error == asio::error::eof) {
                if (!(--retries)) {
                    throw std::logic_error("Timeout");
                    break;
                }
                UE_LOG(LogTemp, Warning, TEXT("EOF, retrying: %d"), retries);
                sleep(1);
                continue;
            } else if (error) {
                throw asio::system_error(error);
            }
        }
        return buf;

    } catch (std::exception& e) {
        connected = false;
        server.tcp_server->start_accept();
        FString error_message(e.what());
        UE_LOG(LogTemp, Warning, TEXT("Caught an exception: %s"), *error_message);

        throw e;
    }
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2008 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

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

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgrePrerequisites.h"
#include "OgreMemoryNedAlloc.h"
#include "OgrePlatformInformation.h"
#include "OgreMemoryTracker.h"

#if OGRE_MEMORY_ALLOCATOR == OGRE_MEMORY_ALLOCATOR_NED

// include ned implementation
#include <nedmalloc.c>

namespace Ogre
{

	//---------------------------------------------------------------------
	void* NedAllocImpl::allocBytes(size_t count,
		const char* file, int line, const char* func)
	{
		void* ptr = nedalloc::nedmalloc(count);
	#if OGRE_MEMORY_TRACKER
		// this alloc policy doesn't do pools (yet, ned can do it)
		MemoryTracker::get()._recordAlloc(ptr, count, 0, file, line, func);
	#else
		// avoid unused params warning
		file;line;func;
	#endif
		return ptr;
	}
	//---------------------------------------------------------------------
	void NedAllocImpl::deallocBytes(void* ptr)
	{
#if OGRE_MEMORY_TRACKER
		MemoryTracker::get()._recordDealloc(ptr);
#endif
		nedalloc::nedfree(ptr);
	}
	//---------------------------------------------------------------------
	void* NedAllocImpl::allocBytesAligned(size_t align, size_t count,
		const char* file, int line, const char* func)
	{
		// default to platform SIMD alignment if none specified
		void* ptr =  align ? nedalloc::nedmemalign(align, count)
			: nedalloc::nedmemalign(OGRE_SIMD_ALIGNMENT, count);
#if OGRE_MEMORY_TRACKER
		// this alloc policy doesn't do pools (yet, ned can do it)
		MemoryTracker::get()._recordAlloc(ptr, count, 0, file, line, func);
#else
		// avoid unused params warning
		file;line;func;
#endif
		return ptr;
	}
	//---------------------------------------------------------------------
	void NedAllocImpl::deallocBytesAligned(size_t align, void* ptr)
	{
#if OGRE_MEMORY_TRACKER
		// this alloc policy doesn't do pools (yet, ned can do it)
		MemoryTracker::get()._recordDealloc(ptr);
#endif
		nedalloc::nedfree(ptr);
	}

}

#endif

<commit_msg>Ned deallocator should deal with null pointers<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2008 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

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

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgrePrerequisites.h"
#include "OgreMemoryNedAlloc.h"
#include "OgrePlatformInformation.h"
#include "OgreMemoryTracker.h"

#if OGRE_MEMORY_ALLOCATOR == OGRE_MEMORY_ALLOCATOR_NED

// include ned implementation
#include <nedmalloc.c>

namespace Ogre
{

	//---------------------------------------------------------------------
	void* NedAllocImpl::allocBytes(size_t count,
		const char* file, int line, const char* func)
	{
		void* ptr = nedalloc::nedmalloc(count);
	#if OGRE_MEMORY_TRACKER
		// this alloc policy doesn't do pools (yet, ned can do it)
		MemoryTracker::get()._recordAlloc(ptr, count, 0, file, line, func);
	#else
		// avoid unused params warning
		file;line;func;
	#endif
		return ptr;
	}
	//---------------------------------------------------------------------
	void NedAllocImpl::deallocBytes(void* ptr)
	{
		// deal with null
		if (!ptr)
			return;
#if OGRE_MEMORY_TRACKER
		MemoryTracker::get()._recordDealloc(ptr);
#endif
		nedalloc::nedfree(ptr);
	}
	//---------------------------------------------------------------------
	void* NedAllocImpl::allocBytesAligned(size_t align, size_t count,
		const char* file, int line, const char* func)
	{
		// default to platform SIMD alignment if none specified
		void* ptr =  align ? nedalloc::nedmemalign(align, count)
			: nedalloc::nedmemalign(OGRE_SIMD_ALIGNMENT, count);
#if OGRE_MEMORY_TRACKER
		// this alloc policy doesn't do pools (yet, ned can do it)
		MemoryTracker::get()._recordAlloc(ptr, count, 0, file, line, func);
#else
		// avoid unused params warning
		file;line;func;
#endif
		return ptr;
	}
	//---------------------------------------------------------------------
	void NedAllocImpl::deallocBytesAligned(size_t align, void* ptr)
	{
		// deal with null
		if (!ptr)
			return;
#if OGRE_MEMORY_TRACKER
		// this alloc policy doesn't do pools (yet, ned can do it)
		MemoryTracker::get()._recordDealloc(ptr);
#endif
		nedalloc::nedfree(ptr);
	}

}

#endif

<|endoftext|>


<commit_before>/*
 * Copyright 2007 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */
#include "vtkPolynomialSolvers.h"

//=============================================================================
int TestPolynomialSolvers(int,char *[])
{
  int testIntValue;

  double P[] = {
    -0.0005, -0.001, 0.05, 0.1, -0.2,
    1., 0., -5.1, 0., 4.,
    -1., .2, 3., 2.2, 2.,
    -7., -.3, 3.8, 14., -16.,
    80., -97.9, 5. };
  double rootInt[] = { -3., 3. };
  int degP = 22;

  testIntValue = vtkPolynomialSolvers::SturmRootCount( P, degP, rootInt );
  if ( testIntValue != 5 )
    {
    vtkGenericWarningMacro("SturmRootCount( -0.0005 x^22 -0.001 x^21 +0.05 x^20 +0.1 x^19 -0.2 x^18 +1 x^17 -5.1 x^15 +4 x^13 -1 x^12 +0.2 x^11 +3 x^10 +2.2 x^9 +2 x^8 -7 x^7 -0.3 x^6 +3.8 x^5 +14 x^4 -16 x^3 +80 x^2 -97.9 x +5, 22, ] -3 ; 3 ] ) = "<<testIntValue<<" != 5");
    return 1;
    }

  double* lowerBnds = new double[degP];
  double tol = 1.e-5;
  testIntValue = vtkPolynomialSolvers::SturmBisectionSolve( P, degP, rootInt, lowerBnds, tol );
  if ( testIntValue != 5 )
    {
    vtkGenericWarningMacro("SturmBisectionSolve( -0.0005 x^22 -0.001 x^21 +0.05 x^20 +0.1 x^19 -0.2 x^18 +1 x^17 -5.1 x^15 +4 x^13 -1 x^12 +0.2 x^11 +3 x^10 +2.2 x^9 +2 x^8 -7 x^7 -0.3 x^6 +3.8 x^5 +14 x^4 -16 x^3 +80 x^2 -97.9 x +5, 22, ] -3 ; 3 ] ) = "<<testIntValue<<" != 5");
    return 1;
    }

  delete [] lowerBnds;

  return 0;
}
<commit_msg>ENH: added test for the Lin-Bairstow solver. STYLE: do not use variable-size arrays when this is not needed.<commit_after>/*
 * Copyright 2007 Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the
 * U.S. Government. Redistribution and use in source and binary forms, with
 * or without modification, are permitted provided that this Notice and any
 * statement of authorship are reproduced on all copies.
 */
#include "vtkPolynomialSolvers.h"

//=============================================================================
int TestPolynomialSolvers(int,char *[])
{
  int testIntValue;

  double P5[] = { 1., -10., 35., -50., 24., 0. } ;
  double roots[5];
  double tol = 1.e-12;
  testIntValue = vtkPolynomialSolvers::LinBairstowSolve( P5, 5, roots, tol );
  if ( testIntValue != 5 )
    {
    vtkGenericWarningMacro("LinBairstowSolve( x**5 -10*x**4 +35*x**3 -50*x**2 +24*x ) = "<<testIntValue<<" != 5");
    return 1;
    }

  double P22[] = {
    -0.0005, -0.001, 0.05, 0.1, -0.2,
    1., 0., -5.1, 0., 4.,
    -1., .2, 3., 2.2, 2.,
    -7., -.3, 3.8, 14., -16.,
    80., -97.9, 5. };
  double rootInt[] = { -3., 3. };

  testIntValue = vtkPolynomialSolvers::SturmRootCount( P22, 22, rootInt );
  if ( testIntValue != 5 )
    {
    vtkGenericWarningMacro("SturmRootCount( -0.0005 x^22 -0.001 x^21 +0.05 x^20 +0.1 x^19 -0.2 x^18 +1 x^17 -5.1 x^15 +4 x^13 -1 x^12 +0.2 x^11 +3 x^10 +2.2 x^9 +2 x^8 -7 x^7 -0.3 x^6 +3.8 x^5 +14 x^4 -16 x^3 +80 x^2 -97.9 x +5, ] -3 ; 3 ] ) = "<<testIntValue<<" != 5");
    return 1;
    }

  double lowerBnds[22];
  tol = 1.e-5;
  testIntValue = vtkPolynomialSolvers::SturmBisectionSolve( P22, 22, rootInt, lowerBnds, tol );
  if ( testIntValue != 5 )
    {
    vtkGenericWarningMacro("SturmBisectionSolve( -0.0005 x^22 -0.001 x^21 +0.05 x^20 +0.1 x^19 -0.2 x^18 +1 x^17 -5.1 x^15 +4 x^13 -1 x^12 +0.2 x^11 +3 x^10 +2.2 x^9 +2 x^8 -7 x^7 -0.3 x^6 +3.8 x^5 +14 x^4 -16 x^3 +80 x^2 -97.9 x +5, ] -3 ; 3 ] ) = "<<testIntValue<<" != 5");
    return 1;
    }

  return 0;
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited
// Copyright (c) 2014-2015 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// appleseed.python headers.
#include "pyseed.h" // has to be first, to avoid redefinition warnings

// appleseed.renderer headers.
#include "renderer/kernel/aov/imagestack.h"
#include "renderer/kernel/aov/tilestack.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/image.h"
#include "foundation/image/pixel.h"
#include "foundation/image/tile.h"
#include "foundation/platform/types.h"

// Standard headers.
#include <algorithm>
#include <cstddef>
#include <string>

namespace bpy = boost::python;
using namespace foundation;
using namespace renderer;

namespace
{
    Tile* copy_tile(const Tile* source)
    {
        return new Tile(*source);
    }

    Tile* deepcopy_tile(const Tile* source, bpy::dict& memo)
    {
        // todo: not sure what to store in memo...
        return new Tile(*source);
    }

    void copy_tile_data_to_py_array(const Tile& tile, bpy::object& buffer)
    {
        void* array = 0;
        Py_ssize_t len;

        const int success = PyObject_AsWriteBuffer(buffer.ptr(), &array, &len);

        if (success != 0)
            bpy::throw_error_already_set();

        if (static_cast<size_t>(len) < tile.get_size())
        {
            PyErr_SetString(PyExc_IndexError, "Buffer size is smaller than data size");
            bpy::throw_error_already_set();
        }

        std::copy(
            tile.get_storage(),
            tile.get_storage() + tile.get_size(),
            reinterpret_cast<uint8*>(array));
    }

    Image* copy_image(const Image* source)
    {
        return new Image(*source);
    }

    Image* deepcopy_image(const Image* source, bpy::dict& memo)
    {
        // todo: not sure what to store in memo...
        return new Image(*source);
    }

    std::string image_stack_get_name(const ImageStack* image_stack, const size_t index)
    {
        return image_stack->get_name(index);
    }
}

void bind_image()
{
    bpy::enum_<PixelFormat>("PixelFormat")
        .value("UInt8",  PixelFormatUInt8)
        .value("UInt16", PixelFormatUInt16)
        .value("UInt32", PixelFormatUInt32)
        .value("Half",   PixelFormatHalf)
        .value("Float",  PixelFormatFloat)
        .value("Double", PixelFormatDouble)
        ;

    bpy::class_<CanvasProperties, boost::noncopyable>("CanvasProperties", bpy::no_init)
        .def_readonly("canvas_width", &CanvasProperties::m_canvas_width)
        .def_readonly("canvas_height", &CanvasProperties::m_canvas_height)
        .def_readonly("tile_width", &CanvasProperties::m_tile_width)
        .def_readonly("tile_height", &CanvasProperties::m_tile_height)
        .def_readonly("channel_count", &CanvasProperties::m_channel_count)
        .def_readonly("pixel_format", &CanvasProperties::m_pixel_format)
        .def_readonly("rcp_canvas_width", &CanvasProperties::m_rcp_canvas_width)
        .def_readonly("rcp_canvas_height", &CanvasProperties::m_rcp_canvas_height)
        .def_readonly("rcp_tile_width", &CanvasProperties::m_rcp_tile_width)
        .def_readonly("rcp_tile_height", &CanvasProperties::m_rcp_tile_height)
        .def_readonly("tile_count_x", &CanvasProperties::m_tile_count_x)
        .def_readonly("tile_count_y", &CanvasProperties::m_tile_count_y)
        .def_readonly("tile_count", &CanvasProperties::m_tile_count)
        .def_readonly("pixel_count", &CanvasProperties::m_pixel_count)
        .def_readonly("pixel_size", &CanvasProperties::m_pixel_size)
        .def("get_tile_width", &CanvasProperties::get_tile_width)
        .def("get_tile_height", &CanvasProperties::get_tile_height)
        ;

    bpy::class_<Tile, boost::noncopyable>("Tile", bpy::init<size_t, size_t, size_t, PixelFormat>())
        .def("__copy__", copy_tile, bpy::return_value_policy<bpy::manage_new_object>())
        .def("__deepcopy__", deepcopy_tile, bpy::return_value_policy<bpy::manage_new_object>())
        .def("get_pixel_format", &Tile::get_pixel_format)
        .def("get_width", &Tile::get_width)
        .def("get_height", &Tile::get_height)
        .def("get_channel_count", &Tile::get_channel_count)
        .def("get_pixel_count", &Tile::get_pixel_count)
        .def("get_size", &Tile::get_size)
        .def("copy_data_to", copy_tile_data_to_py_array)   // todo: maybe this needs a better name
        ;

    const Tile& (Image::*image_get_tile)(const size_t, const size_t) const = &Image::tile;

    bpy::class_<Image, boost::noncopyable>("Image", bpy::no_init)
        .def("__copy__", copy_image, bpy::return_value_policy<bpy::manage_new_object>())
        .def("__deepcopy__", copy_image, bpy::return_value_policy<bpy::manage_new_object>())
        .def("properties", &Image::properties, bpy::return_value_policy<bpy::reference_existing_object>())
        .def("tile", image_get_tile, bpy::return_value_policy<bpy::reference_existing_object>())
        ;

    const Image& (ImageStack::*image_stack_get_image)(const size_t) const = &ImageStack::get_image;

    bpy::class_<ImageStack, boost::noncopyable>("ImageStack", bpy::no_init)
        .def("empty", &ImageStack::empty)
        .def("size", &ImageStack::size)
        .def("get_name", image_stack_get_name)
        .def("get_image", image_stack_get_image, bpy::return_value_policy<bpy::reference_existing_object>())
        ;
}
<commit_msg>Added conversion from Tiles to blender image data.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited
// Copyright (c) 2014-2015 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// appleseed.python headers.
#include "pyseed.h" // has to be first, to avoid redefinition warnings

// appleseed.renderer headers.
#include "renderer/kernel/aov/imagestack.h"
#include "renderer/kernel/aov/tilestack.h"

// appleseed.foundation headers.
#include "foundation/image/canvasproperties.h"
#include "foundation/image/image.h"
#include "foundation/image/pixel.h"
#include "foundation/image/tile.h"
#include "foundation/platform/types.h"

// Standard headers.
#include <algorithm>
#include <cstddef>
#include <string>

namespace bpy = boost::python;
using namespace foundation;
using namespace renderer;

namespace
{
    Tile* copy_tile(const Tile* source)
    {
        return new Tile(*source);
    }

    Tile* deepcopy_tile(const Tile* source, bpy::dict& memo)
    {
        // todo: not sure what to store in memo...
        return new Tile(*source);
    }

    void copy_tile_data_to_py_buffer(const Tile& tile, bpy::object& buffer)
    {
        void* array = 0;
        Py_ssize_t len;

        const int success = PyObject_AsWriteBuffer(buffer.ptr(), &array, &len);

        if (success != 0)
            bpy::throw_error_already_set();

        if (static_cast<size_t>(len) < tile.get_size())
        {
            PyErr_SetString(PyExc_IndexError, "Buffer size is smaller than data size");
            bpy::throw_error_already_set();
        }

        std::copy(
            tile.get_storage(),
            tile.get_storage() + tile.get_size(),
            reinterpret_cast<uint8*>(array));
    }

    bpy::list blender_tile_data(const Tile& tile)
    {
        bpy::list pixels;

        for (size_t y = 0, height = tile.get_height(); y < height; ++y)
        {
            for (size_t x = 0, xe = tile.get_width(); x < xe; ++x)
            {
                // Blender's image coordinate system is y up.
                Color4f linear_rgba;
                tile.get_pixel(x, height - y - 1, linear_rgba);

                bpy::list p;
                p.append(linear_rgba[0]);
                p.append(linear_rgba[1]);
                p.append(linear_rgba[2]);
                p.append(linear_rgba[3]);
                pixels.append(p);
            }
        }

        return pixels;
    }

    Image* copy_image(const Image* source)
    {
        return new Image(*source);
    }

    Image* deepcopy_image(const Image* source, bpy::dict& memo)
    {
        // todo: not sure what to store in memo...
        return new Image(*source);
    }

    std::string image_stack_get_name(const ImageStack* image_stack, const size_t index)
    {
        return image_stack->get_name(index);
    }
}

void bind_image()
{
    bpy::enum_<PixelFormat>("PixelFormat")
        .value("UInt8",  PixelFormatUInt8)
        .value("UInt16", PixelFormatUInt16)
        .value("UInt32", PixelFormatUInt32)
        .value("Half",   PixelFormatHalf)
        .value("Float",  PixelFormatFloat)
        .value("Double", PixelFormatDouble)
        ;

    bpy::class_<CanvasProperties, boost::noncopyable>("CanvasProperties", bpy::no_init)
        .def_readonly("canvas_width", &CanvasProperties::m_canvas_width)
        .def_readonly("canvas_height", &CanvasProperties::m_canvas_height)
        .def_readonly("tile_width", &CanvasProperties::m_tile_width)
        .def_readonly("tile_height", &CanvasProperties::m_tile_height)
        .def_readonly("channel_count", &CanvasProperties::m_channel_count)
        .def_readonly("pixel_format", &CanvasProperties::m_pixel_format)
        .def_readonly("rcp_canvas_width", &CanvasProperties::m_rcp_canvas_width)
        .def_readonly("rcp_canvas_height", &CanvasProperties::m_rcp_canvas_height)
        .def_readonly("rcp_tile_width", &CanvasProperties::m_rcp_tile_width)
        .def_readonly("rcp_tile_height", &CanvasProperties::m_rcp_tile_height)
        .def_readonly("tile_count_x", &CanvasProperties::m_tile_count_x)
        .def_readonly("tile_count_y", &CanvasProperties::m_tile_count_y)
        .def_readonly("tile_count", &CanvasProperties::m_tile_count)
        .def_readonly("pixel_count", &CanvasProperties::m_pixel_count)
        .def_readonly("pixel_size", &CanvasProperties::m_pixel_size)
        .def("get_tile_width", &CanvasProperties::get_tile_width)
        .def("get_tile_height", &CanvasProperties::get_tile_height)
        ;

    bpy::class_<Tile, boost::noncopyable>("Tile", bpy::init<size_t, size_t, size_t, PixelFormat>())
        .def("__copy__", copy_tile, bpy::return_value_policy<bpy::manage_new_object>())
        .def("__deepcopy__", deepcopy_tile, bpy::return_value_policy<bpy::manage_new_object>())
        .def("get_pixel_format", &Tile::get_pixel_format)
        .def("get_width", &Tile::get_width)
        .def("get_height", &Tile::get_height)
        .def("get_channel_count", &Tile::get_channel_count)
        .def("get_pixel_count", &Tile::get_pixel_count)
        .def("get_size", &Tile::get_size)
        .def("copy_data_to", copy_tile_data_to_py_buffer)   // todo: maybe this needs a better name

        .def("blender_tile_data", blender_tile_data)
        ;

    const Tile& (Image::*image_get_tile)(const size_t, const size_t) const = &Image::tile;

    bpy::class_<Image, boost::noncopyable>("Image", bpy::no_init)
        .def("__copy__", copy_image, bpy::return_value_policy<bpy::manage_new_object>())
        .def("__deepcopy__", copy_image, bpy::return_value_policy<bpy::manage_new_object>())
        .def("properties", &Image::properties, bpy::return_value_policy<bpy::reference_existing_object>())
        .def("tile", image_get_tile, bpy::return_value_policy<bpy::reference_existing_object>())
        ;

    const Image& (ImageStack::*image_stack_get_image)(const size_t) const = &ImageStack::get_image;

    bpy::class_<ImageStack, boost::noncopyable>("ImageStack", bpy::no_init)
        .def("empty", &ImageStack::empty)
        .def("size", &ImageStack::size)
        .def("get_name", image_stack_get_name)
        .def("get_image", image_stack_get_image, bpy::return_value_policy<bpy::reference_existing_object>())
        ;
}
<|endoftext|>


<commit_before><commit_msg>added missing namespaces<commit_after><|endoftext|>


<commit_before>/*
    Copyright (c) 2007 Cyrus Daboo. 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 "JXTabs.h"

#include "CDrawUtils.h"
#include "JXTabButton.h"

#include <JXFontManager.h>
#include <jXGlobals.h>

#include <algorithm>

/******************************************************************************
 Constructor

 ******************************************************************************/

const JSize cTabButtonHeight = 25;
const JSize cTabButtonWidthXtra = 16;
const JSize cTabButtonIconWidth = 18;
const JSize cCardsTop = cTabButtonHeight - 2;

JXTabs::JXTabs
	(
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXRadioGroup(enclosure, hSizing, vSizing, x,y, w,h), mBtns(JPtrArrayT::kForgetAll)
{
	SetBorderWidth(0);

	// Always create the card holder
	mCards = new JXTabCardFile(this, JXWidget::kHElastic, JXWidget::kVElastic, 0, cCardsTop, w, h - cCardsTop);

	// Always listen to ourself
	ListenTo(this);
}

/******************************************************************************
 Destructor

 ******************************************************************************/

JXTabs::~JXTabs()
{
}

void JXTabs::AppendCard(JXWidgetSet* card, const char* title, JIndex icon)
{
	// Add the card
	if (card)
		mCards->AppendCard(card);

	// Create a button and add to top
	JIndex cardno = mBtns.GetElementCount() + 1;

	// Determine width of button from title and icon
	JSize start_width = cTabButtonWidthXtra +
					GetFontManager()->GetStringWidth(JGetDefaultFontName(), kJXDefaultFontSize, JFontStyle(), title);

	// Move other buttons and reset their IDs
	JCoordinate btn_start = 0;
	for(JIndex idx = 1; idx <= mBtns.GetElementCount(); idx++)
		btn_start += GetTabButton(idx)->GetFrameWidth();

	JXTabButton* btn = new JXTabButton(cardno, title, this, JXWidget::kFixedLeft, JXWidget::kFixedTop,
										btn_start, 0, start_width, cTabButtonHeight);
	btn->SetIcon(icon);

	mBtns.Append(btn);
	ListenTo(btn);

	Refresh();
}

void JXTabs::ShowCard(JIndex index)
{
	if (mCards->GetCardCount())
		mCards->ShowCard(index);
}

void JXTabs::ActivateCard(JIndex index)
{
	// Activate the button
	GetTabButton(index)->Activate();
}

void JXTabs::DeactivateCard(JIndex index)
{
	// Deactivate the button
	GetTabButton(index)->Deactivate();
}

void JXTabs::SetIconCard(JIndex index, JIndex icon)
{
	// Only if different
	if (GetTabButton(index)->GetIcon() != icon)
	{
		// Change the icon
		JXTabButton* btn = GetTabButton(index);
		JCoordinate old_width = btn->GetFrameWidth();
		btn->SetIcon(icon);
		JCoordinate new_width = btn->GetFrameWidth();

		// Move other buttons and reset their IDs
		for(JIndex idx = index + 1; idx <= mBtns.GetElementCount(); idx++)
			GetTabButton(idx)->Move(new_width - old_width, 0);
	}
}

void JXTabs::RemoveCard(JIndex index)
{
	// Delete and remove the card widget
	if (mCards->GetCardCount())
		mCards->DeleteCard(index);

	// Remove the button and shift the others
	JXContainer* btn = GetTabButton(index);

	// Get its width
	JCoordinate width = btn->GetFrameWidth();

	// Move other buttons and reset their IDs
	for(JIndex idx = index + 1; idx <= mBtns.GetElementCount(); idx++)
	{
		GetTabButton(idx)->Move(-width, 0);
		GetTabButton(idx)->SetID(idx - 1);
	}

	// Remove the button from the radio group object as well
	itsButtons->RemoveElement(index);
	if (itsSelection == btn)
		itsSelection = NULL;

	// Now remove the button
	mBtns.DeleteElement(index);

	Refresh();
}

void JXTabs::RenameCard(JIndex index, const char* title, JIndex icon)
{
	// Get current button width
	JSize oldtext_width = GetTabButton(index)->GetFrameWidth() - ((GetTabButton(index)->GetIcon() > 0) ? cTabButtonIconWidth : 0);
	JSize oldwidth = GetTabButton(index)->GetFrameWidth();

	// Determine width of button from new title
	JSize newtext_width = cTabButtonWidthXtra +
					GetFontManager()->GetStringWidth(JGetDefaultFontName(), kJXDefaultFontSize, JFontStyle(), title);
	JSize newwidth = newtext_width + (icon ? cTabButtonIconWidth : 0);

	// Rename the button
	GetTabButton(index)->SetLabel(title);
	GetTabButton(index)->SetIcon(icon);

	// Change its width
	if (newwidth != oldwidth)
	{
		JSize move_by = newwidth - oldwidth;

		// Move others right before increasing width
		if (move_by > 0)
		{
			for(JIndex i = index + 1; i <= GetTabCount(); i++)
				GetTabButton(i)->Move(move_by, 0);
		}

		// Now change button width (only by amount of text change - icon effect already takn care of)
		GetTabButton(index)->AdjustSize(newtext_width - oldtext_width, 0);

		// Move others left after decreasing width
		if (move_by < 0)
		{
			for(JIndex i = index + 1; i <= GetTabCount(); i++)
				GetTabButton(i)->Move(move_by, 0);
		}
	}
}

void JXTabs::MoveCard(JIndex oldindex, JIndex newindex)
{
	// Check current selected item
	JIndex selected = GetSelectedItem();

	// Get current card at oldindex
	JXWidgetSet* card = mCards->GetCardCount() ? mCards->RemoveCard(oldindex) : NULL;

	// Get current label and icon
	JString old_str = *GetTabButton(oldindex)->GetLabel();
	JIndex old_icon = GetTabButton(oldindex)->GetIcon();

	// Now shift others into old index
	long direction = (newindex > oldindex ? 1 : -1);
	for(unsigned long i = oldindex; i != newindex; i += direction)
	{
		JString str = *GetTabButton(i + direction)->GetLabel();
		JIndex icon = GetTabButton(i + direction)->GetIcon();
		RenameCard(i, str, icon);
	}

	// Write old one into new position
	RenameCard(newindex, old_str, old_icon);

	// Reinsert old card at new position
	if (card)
		mCards->InsertCard(newindex, card);

	// Now change the value if it moved
	if ((selected >= std::min(oldindex, newindex)) && (selected <= std::max(oldindex, newindex)))
	{
		if (selected == oldindex)
		{
			SelectItem(newindex);
			ShowCard(newindex);
		}
		else
		{
			SelectItem(selected - direction);
			ShowCard(selected - direction);
		}
	}
}

void JXTabs::HandleMouseDown(const JPoint& pt, const JXMouseButton button, const JSize clickCount,
									const JXButtonStates& buttonStates, const JXKeyModifiers& modifiers)
{
	// Look for right-click
	if (button == kJXRightButton)
		// Broadcast the right-click
		OnRightClick(0, pt, buttonStates, modifiers);
	else
		// Do default
		JXRadioGroup::HandleMouseDown(pt, button, clickCount, buttonStates, modifiers);
}

void JXTabs::Receive(JBroadcaster* sender, const Message& message)
{
	if (message.Is(JXRadioGroup::kSelectionChanged) && (sender == this))
	{
		// Change the card
		JIndex index = dynamic_cast<const JXRadioGroup::SelectionChanged*>(&message)->GetID();
		ShowCard(index);

		// Do this to force refresh of buttons so that
		// buttons next to the selected one get redrawn properly
		Refresh();
	}
	else if (message.Is(JXTabButton::kRightClick))
	{
		// Find card index
		JIndex index = 1;
		for(; index <= mBtns.GetElementCount(); index++)
		{
			if (GetTabButton(index) == sender)
			{
				// Get the right-click message
				const JXTabButton::RightClick* rclick = dynamic_cast<const JXTabButton::RightClick*>(&message);

				// Adjust point by ofset of button
				JPoint adjust_pt(rclick->GetPt());
				adjust_pt.x += GetTabButton(index)->GetBoundsGlobal().left - GetBoundsGlobal().left;

				// Now do the action
				OnRightClick(index, adjust_pt, rclick->GetButtonStates(), rclick->GetModifiers());
				break;
			}
		}
	}
	else if (message.Is(JXTabButton::kShiftClick))
	{
		// Find card index
		JIndex index = 1;
		for(; index <= mBtns.GetElementCount(); index++)
		{
			if (GetTabButton(index) == sender)
			{
				OnShiftClick(index);
				break;
			}
		}
	}
}

void JXTabs::OnRightClick(JIndex index, const JPoint& pt, const JXButtonStates& buttonStates, const JXKeyModifiers& modifiers)
{
	// Nothing to do in this class
}

void JXTabs::OnShiftClick(JIndex index)
{
	// Nothing to do in this class
}
<commit_msg>Fix problem with names changing to digits when moving tabs.<commit_after>/*
    Copyright (c) 2007-2011 Cyrus Daboo. 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 "JXTabs.h"

#include "CDrawUtils.h"
#include "JXTabButton.h"

#include <JXFontManager.h>
#include <jXGlobals.h>

#include <algorithm>

/******************************************************************************
 Constructor

 ******************************************************************************/

const JSize cTabButtonHeight = 25;
const JSize cTabButtonWidthXtra = 16;
const JSize cTabButtonIconWidth = 18;
const JSize cCardsTop = cTabButtonHeight - 2;

JXTabs::JXTabs
	(
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXRadioGroup(enclosure, hSizing, vSizing, x,y, w,h), mBtns(JPtrArrayT::kForgetAll)
{
	SetBorderWidth(0);

	// Always create the card holder
	mCards = new JXTabCardFile(this, JXWidget::kHElastic, JXWidget::kVElastic, 0, cCardsTop, w, h - cCardsTop);

	// Always listen to ourself
	ListenTo(this);
}

/******************************************************************************
 Destructor

 ******************************************************************************/

JXTabs::~JXTabs()
{
}

void JXTabs::AppendCard(JXWidgetSet* card, const char* title, JIndex icon)
{
	// Add the card
	if (card)
		mCards->AppendCard(card);

	// Create a button and add to top
	JIndex cardno = mBtns.GetElementCount() + 1;

	// Determine width of button from title and icon
	JSize start_width = cTabButtonWidthXtra +
					GetFontManager()->GetStringWidth(JGetDefaultFontName(), kJXDefaultFontSize, JFontStyle(), title);

	// Move other buttons and reset their IDs
	JCoordinate btn_start = 0;
	for(JIndex idx = 1; idx <= mBtns.GetElementCount(); idx++)
		btn_start += GetTabButton(idx)->GetFrameWidth();

	JXTabButton* btn = new JXTabButton(cardno, title, this, JXWidget::kFixedLeft, JXWidget::kFixedTop,
										btn_start, 0, start_width, cTabButtonHeight);
	btn->SetIcon(icon);

	mBtns.Append(btn);
	ListenTo(btn);

	Refresh();
}

void JXTabs::ShowCard(JIndex index)
{
	if (mCards->GetCardCount())
		mCards->ShowCard(index);
}

void JXTabs::ActivateCard(JIndex index)
{
	// Activate the button
	GetTabButton(index)->Activate();
}

void JXTabs::DeactivateCard(JIndex index)
{
	// Deactivate the button
	GetTabButton(index)->Deactivate();
}

void JXTabs::SetIconCard(JIndex index, JIndex icon)
{
	// Only if different
	if (GetTabButton(index)->GetIcon() != icon)
	{
		// Change the icon
		JXTabButton* btn = GetTabButton(index);
		JCoordinate old_width = btn->GetFrameWidth();
		btn->SetIcon(icon);
		JCoordinate new_width = btn->GetFrameWidth();

		// Move other buttons and reset their IDs
		for(JIndex idx = index + 1; idx <= mBtns.GetElementCount(); idx++)
			GetTabButton(idx)->Move(new_width - old_width, 0);
	}
}

void JXTabs::RemoveCard(JIndex index)
{
	// Delete and remove the card widget
	if (mCards->GetCardCount())
		mCards->DeleteCard(index);

	// Remove the button and shift the others
	JXContainer* btn = GetTabButton(index);

	// Get its width
	JCoordinate width = btn->GetFrameWidth();

	// Move other buttons and reset their IDs
	for(JIndex idx = index + 1; idx <= mBtns.GetElementCount(); idx++)
	{
		GetTabButton(idx)->Move(-width, 0);
		GetTabButton(idx)->SetID(idx - 1);
	}

	// Remove the button from the radio group object as well
	itsButtons->RemoveElement(index);
	if (itsSelection == btn)
		itsSelection = NULL;

	// Now remove the button
	mBtns.DeleteElement(index);

	Refresh();
}

void JXTabs::RenameCard(JIndex index, const char* title, JIndex icon)
{
	// Get current button width
	JSize oldtext_width = GetTabButton(index)->GetFrameWidth() - ((GetTabButton(index)->GetIcon() > 0) ? cTabButtonIconWidth : 0);
	JSize oldwidth = GetTabButton(index)->GetFrameWidth();

	// Determine width of button from new title
	JSize newtext_width = cTabButtonWidthXtra +
					GetFontManager()->GetStringWidth(JGetDefaultFontName(), kJXDefaultFontSize, JFontStyle(), title);
	JSize newwidth = newtext_width + (icon ? cTabButtonIconWidth : 0);

	// Rename the button
	GetTabButton(index)->SetLabel(title);
	GetTabButton(index)->SetIcon(icon);

	// Change its width
	if (newwidth != oldwidth)
	{
		JSize move_by = newwidth - oldwidth;

		// Move others right before increasing width
		if (move_by > 0)
		{
			for(JIndex i = index + 1; i <= GetTabCount(); i++)
				GetTabButton(i)->Move(move_by, 0);
		}

		// Now change button width (only by amount of text change - icon effect already takn care of)
		GetTabButton(index)->AdjustSize(newtext_width - oldtext_width, 0);

		// Move others left after decreasing width
		if (move_by < 0)
		{
			for(JIndex i = index + 1; i <= GetTabCount(); i++)
				GetTabButton(i)->Move(move_by, 0);
		}
	}
}

void JXTabs::MoveCard(JIndex oldindex, JIndex newindex)
{
	// Check current selected item
	JIndex selected = GetSelectedItem();

	// Get current card at oldindex
	JXWidgetSet* card = mCards->GetCardCount() ? mCards->RemoveCard(oldindex) : NULL;

	// Get current label and icon
	JString old_str = GetTabButton(oldindex)->GetLabel();
	JIndex old_icon = GetTabButton(oldindex)->GetIcon();

	// Now shift others into old index
	long direction = (newindex > oldindex ? 1 : -1);
	for(unsigned long i = oldindex; i != newindex; i += direction)
	{
		JString str = GetTabButton(i + direction)->GetLabel();
		JIndex icon = GetTabButton(i + direction)->GetIcon();
		RenameCard(i, str, icon);
	}

	// Write old one into new position
	RenameCard(newindex, old_str, old_icon);

	// Reinsert old card at new position
	if (card)
		mCards->InsertCard(newindex, card);

	// Now change the value if it moved
	if ((selected >= std::min(oldindex, newindex)) && (selected <= std::max(oldindex, newindex)))
	{
		if (selected == oldindex)
		{
			SelectItem(newindex);
			ShowCard(newindex);
		}
		else
		{
			SelectItem(selected - direction);
			ShowCard(selected - direction);
		}
	}
}

void JXTabs::HandleMouseDown(const JPoint& pt, const JXMouseButton button, const JSize clickCount,
									const JXButtonStates& buttonStates, const JXKeyModifiers& modifiers)
{
	// Look for right-click
	if (button == kJXRightButton)
		// Broadcast the right-click
		OnRightClick(0, pt, buttonStates, modifiers);
	else
		// Do default
		JXRadioGroup::HandleMouseDown(pt, button, clickCount, buttonStates, modifiers);
}

void JXTabs::Receive(JBroadcaster* sender, const Message& message)
{
	if (message.Is(JXRadioGroup::kSelectionChanged) && (sender == this))
	{
		// Change the card
		JIndex index = dynamic_cast<const JXRadioGroup::SelectionChanged*>(&message)->GetID();
		ShowCard(index);

		// Do this to force refresh of buttons so that
		// buttons next to the selected one get redrawn properly
		Refresh();
	}
	else if (message.Is(JXTabButton::kRightClick))
	{
		// Find card index
		JIndex index = 1;
		for(; index <= mBtns.GetElementCount(); index++)
		{
			if (GetTabButton(index) == sender)
			{
				// Get the right-click message
				const JXTabButton::RightClick* rclick = dynamic_cast<const JXTabButton::RightClick*>(&message);

				// Adjust point by ofset of button
				JPoint adjust_pt(rclick->GetPt());
				adjust_pt.x += GetTabButton(index)->GetBoundsGlobal().left - GetBoundsGlobal().left;

				// Now do the action
				OnRightClick(index, adjust_pt, rclick->GetButtonStates(), rclick->GetModifiers());
				break;
			}
		}
	}
	else if (message.Is(JXTabButton::kShiftClick))
	{
		// Find card index
		JIndex index = 1;
		for(; index <= mBtns.GetElementCount(); index++)
		{
			if (GetTabButton(index) == sender)
			{
				OnShiftClick(index);
				break;
			}
		}
	}
}

void JXTabs::OnRightClick(JIndex index, const JPoint& pt, const JXButtonStates& buttonStates, const JXKeyModifiers& modifiers)
{
	// Nothing to do in this class
}

void JXTabs::OnShiftClick(JIndex index)
{
	// Nothing to do in this class
}
<|endoftext|>


<commit_before>#ifndef GUARD_identity_map_hpp
#define GUARD_identity_map_hpp

#include "handle.hpp"
#include <boost/noncopyable.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <cassert>
#include <map>
#include <stdexcept>

#ifndef DEBUG
	#include <jewel/debug_log.hpp>
	#include <iostream>
	#include <typeinfo>
#endif

namespace sqloxx
{

/**
 * Provides an in-memory cache for objects of type T, where such
 * objects are persisted to a database via a database connection of
 * type Connection. T and Connection are passed as template parameters
 * to the class template. It is expected that T is a subclass of
 * sqloxx::PersistentObject<T, Connection>, and Connection is a
 * subclass of sqloxx::DatabaseConnection.
 *
 * Each instance of IdentityMap has a particular Connection associated
 * with it. The IdentityMap caches objects loaded from the database,
 * and provides clients - in particular the sqloxx::Handle<T> class -
 * pointers to these objects. By using IdentityMap to cache objects,
 * application code can be sure that each single record of type T
 * that is stored in the database, has at most a single in-memory
 * object of type T associated with that record, loaded in memory
 * at any one time. IdentityMap thus implements the "Identity Map"
 * pattern detailed in Martin Fowler's book, "Patterns of Enterprise
 * Application Architecture". By having at most a single in-memory
 * object per in-database record, we guard against the possibility
 * of the same object being edited inconsistently in different
 * locations. By keeping objects in a cache, we speed execution of
 * read and write operations, by avoiding a trip to the disk when an
 * object has already been loaded.
 *
 * IdentityMap is intended to work in conjunction with sqloxx::Handle<T>
 * and sqloxx::PersistentObject<T, Connection>. See also the documentation
 * for those classes.
 *
 * @todo Documentation and testing.
 */
template <typename T, typename Connection>
class IdentityMap
{
public:

	typedef typename T::Id Id;
	typedef typename T::Id CacheKey;

	/**
	 * Construct an IdentityMap associated with the database
	 * connection Connection. Connection should be a subclass
	 * of sqloxx::DatabaseConnection.
	 *
	 * @throws std::bad_alloc in the case of memory allocation
	 * failure. (This is very unlikely.)
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	IdentityMap(Connection& p_connection);

	/**
	 * Copy constructor. Performs a shallow copy. The underlying
	 * structures (e.g. database connection and cache) employed
	 * by the new IdentityMap will be the very same as those employed
	 * by rhs.
	 *
	 * Exception safety: nothrow guarantee.
	 */
	IdentityMap(IdentityMap const& rhs);

	/**
	 * Destructor. The underlying cache is automatically emptied
	 * of all objects (i.e. instances of T) on destruction of
	 * the IdentityMap, by the calling the destructor of each
	 * object in the cache. The cache is then itself destructed.
	 * However the database connection (Connection instance) referenced
	 * by the IdentityMap is \e not destructed merely by virtue
	 * of the destruction of the IdentityMap.
	 *
	 * Exception safety: the nothrow guarantee is provided,
	 * providing the destructor of T does not throw.
	 *
	 * @todo Testing.
	 */
	~IdentityMap();

	/**
	 * Assignment is shallow, and with semantics like those of the
	 * copy constructor.
	 *
	 * Exception safety: nothrow guarantee.
	 *
	 * @todo Testing.
	 */
	IdentityMap& operator=(IdentityMap const& rhs);

	/**
	 * Provide handle to object of type T, representing a newly created object
	 * that has not yet been persisted to the database.
	 *
	 * @returns a Handle<T> pointing to a newly constructed instance of T,
	 * that is cached in this instance of IdentityMap<T, Connection>.
	 *
	 * @throws std::bad_alloc in the unlikely event of memory allocation
	 * failure during the creating and caching of the instance of T.
	 *
	 * In addition, any exceptions thrown from the T constructor
	 * of the form T(IdentityMap<T, Connection>&) may also be thrown
	 * from provide_object().
	 *
	 * Exception safety depends on the constructor of T of the form
	 * T(IdentityMap<T, Connection>&). Provided this constructor offers at
	 * least the strong guarantee, then provide_object() offers the
	 * strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle<T> provide_object();

	/**
	 * Provide handle to object of type T, representing an object
	 * already stored in the database, with primary key (id) p_id.
	 */
	Handle<T> provide_object(Id p_id);

	/**
	 * Register id of newly saved instance of T. This function is
	 * intended only to be called from PersistentObject<T, Connection>.
	 */
	void register_id(CacheKey cache_key, Id allocated_id);

	/**
	 * Notify the IdentityMap that there are no handles left that are
	 * pointing to this object.
	 */
	void notify_nil_handles(CacheKey cache_key);

	void enable_caching();

	void disable_caching();

	/**
	 * @returns a reference to the database connection with which
	 * this IdentityMap is associated.
	 *
	 * Exception safety: nothrow guarantee.
	 *
	 * @todo Testing.
	 */
	Connection& connection();

private:

	void uncache_object_proxied(CacheKey cache_key);

	// Find the next available cache key
	// WARNING Move the implementation out of the class body.
	/**
	 * @throws sqloxx::OverflowException if the cache has reached
	 * its maximum size (extremely unlikely).
	 *
	 * Exception safety: strong guarantee.
	 */
	CacheKey provide_cache_key();

	typedef typename boost::shared_ptr<T> Record;
	typedef boost::unordered_map<Id, Record> IdMap;
	typedef std::map<CacheKey, Record> CacheKeyMap;

	/**
	 * Returns a reference to the underlying cache in which objects
	 * are indexed by CacheKey (as opposed to Id, which does not apply
	 * to objects not yet persisted to the database.
	 *
	 * Exception safety: nothrow guarantee.
	 */
	CacheKeyMap& cache_key_map() const
	{
		return m_map_data->cache_key_map;
	}

	/**
	 * Returns a reference to the underlying cache in which objectsa
	 * are indexed Id (ass opposed to CacheKey.
	 *
	 * ExceptioSafety: <nothrow guarantee
	 */
	IdMap& id_map() const
	{
		return m_map_data->id_map;
	}

	CacheKey& last_cache_key() const
	{
		return m_map_data->last_cache_key;
	}

	bool& is_caching() const
	{
		return m_map_data->is_caching;
	}

	// Data members

	// Hold data in a pimpl struct merely to facilitate safe, shallow copying.
	struct MapData
	{
		MapData(Connection& p_connection):
			connection(p_connection),
			last_cache_key(0),
			is_caching(false)
		{
		}

		// Provides index to all cached objects, including those not as yet
		// saved to the database.
		CacheKeyMap cache_key_map;

		// Provides index to objects that have been persisted to the database,
		// indexed by their primary key in the database.
		IdMap id_map;

		// The database connection with which this IdentityMap is associated.
		Connection& connection;

		// The last key to be assigned as in index into cache_key_map - or
		// 0 if none have been assigned.
		CacheKey last_cache_key;

		// Indicates whether the IdentityMap is currently
		// holding objects indefinitely in the cache (m_caching == true),
		// or whether it is
		// clearing each object out when there are no longer handles
		// pointing to it (m_caching == false).
		bool is_caching;
	};
	boost::shared_ptr<MapData> m_map_data;
};

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>::IdentityMap(Connection& p_connection):
	m_map_data(new MapData(p_connection))
{
}

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>::IdentityMap(IdentityMap const& rhs):
	m_map_data(rhs.m_map_data)
{
}

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>::~IdentityMap()
{
}

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>&
IdentityMap<T, Connection>::operator=(IdentityMap const& rhs)
{
	m_map_data = rhs.m_map_data;
	return *this;
}

template <typename T, typename Connection>
Handle<T>
IdentityMap<T, Connection>::provide_object()
{
	// Comments here are to help ascertain exception-safety.
	Record obj_ptr(new T(*this));  // T-dependent exception safety
	CacheKey const cache_key = provide_cache_key(); // strong guarantee
	obj_ptr->set_cache_key(cache_key);  // nothrow

	// In the next statement:
	// constructing the pair of CacheKeyMap::value_type is nothrow; and
	// calling insert either (a) succeeds, or (b) fails completely and
	// throws std::bad_alloc. If it throws, then obj_ptr
	// will be deleted on exit (as it's a shared_ptr) - which amounts to
	// rollback of provide_object().
	/* Except it caused a segfault...
	cache_key_map().insert
	(	typename CacheKeyMap::value_type(cache_key, obj_ptr)
	);
	*/
	cache_key_map()[cache_key] = obj_ptr;

	// get() is nothrow. The Handle<T> constructor and copy constructor
	// can throw in some (very unlikely) circumstances, namely when there
	// are too many Handle<T> instances pointing to this T; but that's not
	// the case here, as we have only just constructed this object and
	// are returning the only Handle so far pointing to it. So returning
	// the return value is nothrow.
	return Handle<T>(obj_ptr.get());
}

template <typename T, typename Connection>
Handle<T>
IdentityMap<T, Connection>::provide_object(Id p_id)
{
	typename IdMap::iterator it = id_map().find(p_id);
	if (it == id_map().end())
	{
		// Then we need to create this object.
		Record obj_ptr(new T(*this, p_id));
		id_map()[p_id] = obj_ptr;
		CacheKey cache_key = provide_cache_key();
		cache_key_map()[cache_key] = obj_ptr;
		obj_ptr->set_cache_key(cache_key);
		return Handle<T>(obj_ptr.get());
	}
	assert (it != id_map().end());
	return Handle<T>(it->second.get());
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::register_id(CacheKey cache_key, Id allocated_id)
{
	id_map()[allocated_id] = cache_key_map()[cache_key];
	return;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::uncache_object_proxied(CacheKey cache_key)
{
	Record const record = cache_key_map().find(cache_key)->second;
	if (record->has_id())
	{
		assert (id_map().find(record->id()) != id_map().end());
		id_map().erase(record->id());
	}
	cache_key_map().erase(cache_key);
	return;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::notify_nil_handles(CacheKey cache_key)
{
	if (!is_caching())
	{
		uncache_object_proxied(cache_key);
	}
	return;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::enable_caching()
{
	is_caching() = true;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::disable_caching()
{
	if (is_caching())
	{
		typename CacheKeyMap::iterator const endpoint = cache_key_map().end();
		for
		(	typename CacheKeyMap::iterator it = cache_key_map().begin();
			it != endpoint;
			++it
		)
		{
			if (it->second->is_orphaned())
			{
				uncache_object_proxied(it->first);
			}
		}
		is_caching() = false;
	}
	return;
}

template <typename T, typename Connection>
inline
Connection&
IdentityMap<T, Connection>::connection()
{
	return m_map_data->connection;
}

template <typename T, typename Connection>
typename IdentityMap<T, Connection>::CacheKey
IdentityMap<T, Connection>::provide_cache_key()
{
	static CacheKey const maximum = std::numeric_limits<CacheKey>::max();
	typename CacheKeyMap::size_type const sz = cache_key_map().size();
	if (sz == 0)
	{
		return last_cache_key() = 1;  // Intentional assignment
	}
	if (sz == boost::numeric_cast<typename CacheKeyMap::size_type>(maximum))
	{
		// There are no more available positive numbers to serve
		// as cache keys. This is extremely unlikely ever to occur.
		// We could possibly avoid throwing here by instead calling
		// disable_caching(), which would trigger an emptying of the cache
		// of any orphaned objects. But the emptying might take a long, long
		// time. So we just throw.
		// Avoid complication by not even considering negative numbers.
		throw OverflowException
		(	"No more cache keys are available for identifying objects "
			"in the IdentityMap."
		);
	}
	CacheKey ret = last_cache_key();
	typedef typename CacheKeyMap::const_iterator Iterator;
	Iterator it = cache_key_map().find(ret);
	Iterator const endpoint = cache_key_map().end();
	if (it == endpoint)
	{
		return last_cache_key();
	}

	// Look for the first available unused key to assign to next_cache_key()
	// ready for the next call to provide_cache_key(). This relies on
	// CacheKeyMap being, or behaving like, std::map, in that it keeps its
	// elements ordered by key.
	assert (cache_key_map().size() > 0);
	while (ret == it->first)
	{
		if (ret == maximum)
		{
			ret = 1;
		}
		else
		{
			++ret;
		}
		++it;
		if (it == endpoint)
		{
			it = cache_key_map().begin();
		}
	}
	assert (cache_key_map().find(ret) == cache_key_map().end());
	return last_cache_key() = ret;  // Intentional assignment
}

}  // namespace sqloxx

#endif  // GUARD_identity_map_hpp
<commit_msg>Further refinements in sqloxx::IdentityMap.<commit_after>#ifndef GUARD_identity_map_hpp
#define GUARD_identity_map_hpp

#include "handle.hpp"
#include <boost/noncopyable.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <cassert>
#include <map>
#include <stdexcept>

#ifndef DEBUG
	#include <jewel/debug_log.hpp>
	#include <iostream>
	#include <typeinfo>
#endif

namespace sqloxx
{

/**
 * Provides an in-memory cache for objects of type T, where such
 * objects are persisted to a database via a database connection of
 * type Connection. T and Connection are passed as template parameters
 * to the class template. It is expected that T is a subclass of
 * sqloxx::PersistentObject<T, Connection>, and Connection is a
 * subclass of sqloxx::DatabaseConnection.
 *
 * Each instance of IdentityMap has a particular Connection associated
 * with it. The IdentityMap caches objects loaded from the database,
 * and provides clients - in particular the sqloxx::Handle<T> class -
 * pointers to these objects. By using IdentityMap to cache objects,
 * application code can be sure that each single record of type T
 * that is stored in the database, has at most a single in-memory
 * object of type T associated with that record, loaded in memory
 * at any one time. IdentityMap thus implements the "Identity Map"
 * pattern detailed in Martin Fowler's book, "Patterns of Enterprise
 * Application Architecture". By having at most a single in-memory
 * object per in-database record, we guard against the possibility
 * of the same object being edited inconsistently in different
 * locations. By keeping objects in a cache, we speed execution of
 * read and write operations, by avoiding a trip to the disk when an
 * object has already been loaded.
 *
 * IdentityMap is intended to work in conjunction with sqloxx::Handle<T>
 * and sqloxx::PersistentObject<T, Connection>. See also the documentation
 * for those classes.
 *
 * @todo Documentation and testing.
 */
template <typename T, typename Connection>
class IdentityMap
{
public:

	typedef typename T::Id Id;
	typedef typename T::Id CacheKey;

	/**
	 * Construct an IdentityMap associated with the database
	 * connection Connection. Connection should be a subclass
	 * of sqloxx::DatabaseConnection.
	 *
	 * @throws std::bad_alloc in the case of memory allocation
	 * failure. (This is very unlikely.)
	 *
	 * Exception safety: strong guarantee.
	 *
	 * @todo Testing.
	 */
	IdentityMap(Connection& p_connection);

	/**
	 * Copy constructor. Performs a shallow copy. The underlying
	 * structures (e.g. database connection and cache) employed
	 * by the new IdentityMap will be the very same as those employed
	 * by rhs.
	 *
	 * Exception safety: nothrow guarantee.
	 */
	IdentityMap(IdentityMap const& rhs);

	/**
	 * Destructor. The underlying cache is automatically emptied
	 * of all objects (i.e. instances of T) on destruction of
	 * the IdentityMap, by the calling the destructor of each
	 * object in the cache. The cache is then itself destructed.
	 * However the database connection (Connection instance) referenced
	 * by the IdentityMap is \e not destructed merely by virtue
	 * of the destruction of the IdentityMap.
	 *
	 * Exception safety: the nothrow guarantee is provided,
	 * providing the destructor of T does not throw.
	 *
	 * @todo Testing.
	 */
	~IdentityMap();

	/**
	 * Assignment is shallow, and with semantics like those of the
	 * copy constructor.
	 *
	 * Exception safety: nothrow guarantee.
	 *
	 * @todo Testing.
	 */
	IdentityMap& operator=(IdentityMap const& rhs);

	/**
	 * Provide handle to object of type T, representing a newly created object
	 * that has not yet been persisted to the database.
	 *
	 * @returns a Handle<T> pointing to a newly constructed instance of T,
	 * that is cached in this instance of IdentityMap<T, Connection>.
	 *
	 * @throws std::bad_alloc in the unlikely event of memory allocation
	 * failure during the creating and caching of the instance of T.
	 *
	 * In addition, any exceptions thrown from the T constructor
	 * of the form T(IdentityMap<T, Connection>&) may also be thrown
	 * from provide_object().
	 *
	 * Exception safety depends on the constructor of T of the form
	 * T(IdentityMap<T, Connection>&). Provided this constructor offers at
	 * least the strong guarantee, then provide_object() offers the
	 * strong guarantee.
	 *
	 * @todo Testing.
	 */
	Handle<T> provide_object();

	/**
	 * Provide handle to object of type T, representing an object
	 * already stored in the database, with primary key (id) p_id.
	 */
	Handle<T> provide_object(Id p_id);

	/**
	 * Register id of newly saved instance of T. This function is
	 * intended only to be called from PersistentObject<T, Connection>.
	 */
	void register_id(CacheKey cache_key, Id allocated_id);

	/**
	 * Notify the IdentityMap that there are no handles left that are
	 * pointing to this object.
	 */
	void notify_nil_handles(CacheKey cache_key);

	void enable_caching();

	void disable_caching();

	/**
	 * @returns a reference to the database connection with which
	 * this IdentityMap is associated.
	 *
	 * Exception safety: nothrow guarantee.
	 *
	 * @todo Testing.
	 */
	Connection& connection();

private:

	void uncache_object_proxied(CacheKey cache_key);

	// Find the next available cache key
	// WARNING Move the implementation out of the class body.
	/**
	 * @throws sqloxx::OverflowException if the cache has reached
	 * its maximum size (extremely unlikely).
	 *
	 * Exception safety: strong guarantee.
	 */
	CacheKey provide_cache_key();

	typedef typename boost::shared_ptr<T> Record;
	typedef boost::unordered_map<Id, Record> IdMap;
	typedef std::map<CacheKey, Record> CacheKeyMap;

	/**
	 * Returns a reference to the underlying cache in which objects
	 * are indexed by CacheKey (as opposed to Id, which does not apply
	 * to objects not yet persisted to the database.
	 *
	 * Exception safety: nothrow guarantee.
	 */
	CacheKeyMap& cache_key_map() const
	{
		return m_map_data->cache_key_map;
	}

	/**
	 * Returns a reference to the underlying cache in which objectsa
	 * are indexed Id (ass opposed to CacheKey.
	 *
	 * ExceptioSafety: <nothrow guarantee
	 */
	IdMap& id_map() const
	{
		return m_map_data->id_map;
	}

	CacheKey& last_cache_key() const
	{
		return m_map_data->last_cache_key;
	}

	bool& is_caching() const
	{
		return m_map_data->is_caching;
	}

	// Data members

	// Hold data in a pimpl struct merely to facilitate safe, shallow copying.
	struct MapData
	{
		MapData(Connection& p_connection):
			connection(p_connection),
			last_cache_key(0),
			is_caching(false)
		{
		}

		// Provides index to all cached objects, including those not as yet
		// saved to the database.
		CacheKeyMap cache_key_map;

		// Provides index to objects that have been persisted to the database,
		// indexed by their primary key in the database.
		IdMap id_map;

		// The database connection with which this IdentityMap is associated.
		Connection& connection;

		// The last key to be assigned as in index into cache_key_map - or
		// 0 if none have been assigned.
		CacheKey last_cache_key;

		// Indicates whether the IdentityMap is currently
		// holding objects indefinitely in the cache (m_caching == true),
		// or whether it is
		// clearing each object out when there are no longer handles
		// pointing to it (m_caching == false).
		bool is_caching;
	};
	boost::shared_ptr<MapData> m_map_data;
};

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>::IdentityMap(Connection& p_connection):
	m_map_data(new MapData(p_connection))
{
}

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>::IdentityMap(IdentityMap const& rhs):
	m_map_data(rhs.m_map_data)
{
}

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>::~IdentityMap()
{
}

template <typename T, typename Connection>
inline
IdentityMap<T, Connection>&
IdentityMap<T, Connection>::operator=(IdentityMap const& rhs)
{
	m_map_data = rhs.m_map_data;
	return *this;
}

template <typename T, typename Connection>
Handle<T>
IdentityMap<T, Connection>::provide_object()
{
	// Comments here are to help ascertain exception-safety.
	Record obj_ptr(new T(*this));  // T-dependent exception safety
	CacheKey const cache_key = provide_cache_key(); // strong guarantee
	obj_ptr->set_cache_key(cache_key);  // nothrow

	// In the next statement:
	// constructing the pair of CacheKeyMap::value_type is nothrow; and
	// calling insert either (a) succeeds, or (b) fails completely and
	// throws std::bad_alloc. If it throws, then obj_ptr
	// will be deleted on exit (as it's a shared_ptr) - which amounts to
	// rollback of provide_object().
	cache_key_map().insert
	(	typename CacheKeyMap::value_type(cache_key, obj_ptr)
	);
	// We could have done the following, but the above is more efficient and
	// less "magical".
	// cache_key_map()[cache_key] = obj_ptr;

	// In the below, get() is nothrow. The Handle<T> constructor and copy
	// constructor can throw in some (very unlikely) circumstances,
	// namely when there are too many Handle<T> instances pointing to
	// this T; but that's not the case here, as we have only just
	// constructed this object and are returning the only Handle so
	// far pointing to it. So returning the return value is nothrow.
	return Handle<T>(obj_ptr.get());
}

template <typename T, typename Connection>
Handle<T>
IdentityMap<T, Connection>::provide_object(Id p_id)
{
	typename IdMap::iterator it = id_map().find(p_id);
	if (it == id_map().end())
	{
		// Then we need to create this object.
		Record obj_ptr(new T(*this, p_id));
		id_map()[p_id] = obj_ptr;
		CacheKey cache_key = provide_cache_key();
		cache_key_map()[cache_key] = obj_ptr;
		obj_ptr->set_cache_key(cache_key);
		return Handle<T>(obj_ptr.get());
	}
	assert (it != id_map().end());
	return Handle<T>(it->second.get());
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::register_id(CacheKey cache_key, Id allocated_id)
{
	id_map()[allocated_id] = cache_key_map()[cache_key];
	return;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::uncache_object_proxied(CacheKey cache_key)
{
	Record const record = cache_key_map().find(cache_key)->second;
	if (record->has_id())
	{
		assert (id_map().find(record->id()) != id_map().end());
		id_map().erase(record->id());
	}
	cache_key_map().erase(cache_key);
	return;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::notify_nil_handles(CacheKey cache_key)
{
	if (!is_caching())
	{
		uncache_object_proxied(cache_key);
	}
	return;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::enable_caching()
{
	is_caching() = true;
}

template <typename T, typename Connection>
void
IdentityMap<T, Connection>::disable_caching()
{
	if (is_caching())
	{
		typename CacheKeyMap::iterator const endpoint = cache_key_map().end();
		for
		(	typename CacheKeyMap::iterator it = cache_key_map().begin();
			it != endpoint;
			++it
		)
		{
			if (it->second->is_orphaned())
			{
				uncache_object_proxied(it->first);
			}
		}
		is_caching() = false;
	}
	return;
}

template <typename T, typename Connection>
inline
Connection&
IdentityMap<T, Connection>::connection()
{
	return m_map_data->connection;
}

template <typename T, typename Connection>
typename IdentityMap<T, Connection>::CacheKey
IdentityMap<T, Connection>::provide_cache_key()
{
	static CacheKey const maximum = std::numeric_limits<CacheKey>::max();
	typename CacheKeyMap::size_type const sz = cache_key_map().size();
	if (sz == 0)
	{
		return last_cache_key() = 1;  // Intentional assignment
	}
	if (sz == boost::numeric_cast<typename CacheKeyMap::size_type>(maximum))
	{
		// There are no more available positive numbers to serve
		// as cache keys. This is extremely unlikely ever to occur.
		// We could possibly avoid throwing here by instead calling
		// disable_caching(), which would trigger an emptying of the cache
		// of any orphaned objects. But the emptying might take a long, long
		// time. So we just throw.
		// Avoid complication by not even considering negative numbers.
		throw OverflowException
		(	"No more cache keys are available for identifying objects "
			"in the IdentityMap."
		);
	}
	CacheKey ret = last_cache_key();
	typedef typename CacheKeyMap::const_iterator Iterator;
	Iterator it = cache_key_map().find(ret);
	Iterator const endpoint = cache_key_map().end();
	if (it == endpoint)
	{
		return last_cache_key();
	}

	// Look for the first available unused key to assign to next_cache_key()
	// ready for the next call to provide_cache_key(). This relies on
	// CacheKeyMap being, or behaving like, std::map, in that it keeps its
	// elements ordered by key.
	assert (cache_key_map().size() > 0);
	while (ret == it->first)
	{
		if (ret == maximum) ret = 1;
		else ++ret;
		if (++it == endpoint) it = cache_key_map().begin();
	}
	assert (cache_key_map().find(ret) == cache_key_map().end());
	return last_cache_key() = ret;  // Intentional assignment
}

}  // namespace sqloxx

#endif  // GUARD_identity_map_hpp
<|endoftext|>


<commit_before>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONDigitCalibrator.h"

#include "AliLog.h"
#include "AliMUONCalibrationData.h"
#include "AliMUONConstants.h"
#include "AliMUONData.h"
#include "AliMUONDigit.h"
#include "AliMUONLogger.h"
#include "AliMUONPadStatusMaker.h"
#include "AliMUONPadStatusMapMaker.h"
#include "AliMUONV2DStore.h"
#include "AliMUONVCalibParam.h"
#include "TClonesArray.h"

/// \class AliMUONDigitCalibrator
/// Class used to calibrate digits (either real or simulated ones).
///
/// The calibration consists of subtracting the pedestal
/// and multiplying by a gain, so that
/// Signal = (ADC-pedestal)*gain
///
/// Please note also that for the moment, if a digit lies on a dead channel
/// we remove this digit from the list of digits.
/// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
/// should in principle flag a digit as bad w/o removing it, but this
/// then requires some changes in the cluster finder to deal with this extra
/// information correctly (e.g. to set a quality for the cluster if it contains
/// bad digits).
///
/// \author Laurent Aphecetche

/// \cond CLASSIMP
ClassImp(AliMUONDigitCalibrator)
/// \endcond

//_____________________________________________________________________________
AliMUONDigitCalibrator::AliMUONDigitCalibrator(AliMUONData* muonData,
                                               AliMUONCalibrationData* calib,
                                               Bool_t createAndUseStatusMap)
: TTask("AliMUONDigitCalibrator","Raw digit calibration"),
  fData(muonData),
  fCalibrationData(calib),
  fStatusMap(0x0),
  fLogger(new AliMUONLogger(1000))
{
    /// ctor. This class needs the muonData to get access to the digit,
    /// and the calibrationData to get access to calibration parameters.

    if (!calib) {
      AliFatal("No calibration data defined");
    }

    if (createAndUseStatusMap)
    {
      AliMUONPadStatusMaker maker(*calib);

      // this is here that we decide on our "goodness" policy, i.e.
      // what do we call an invalid pad (a pad maybe bad because it's HV
      // was too low, or its pedestals too high, etc..)
      //
      maker.SetHVSt12Limits(1300,1600);
      maker.SetHVSt345Limits(1500,2000);
      maker.SetPedMeanLimits(50,200);
      maker.SetPedSigmaLimits(0.1,3);

      // From this set of limits, compute the status of all tracker pads.
      AliMUONV2DStore* status = maker.MakeStatus();
      // we do not check that status is != 0x0, as this is supposed to be
      // the responsability of the padStatusMaker.

      AliMUONPadStatusMapMaker mapMaker;

      Int_t mask(0x8080);
      //FIXME: kind of fake one for the moment, we consider dead only
      // if ped and/or hv value missing.
      //WARNING : getting this mask wrong is a very effective way of getting
      //no digits at all out of this class ;-)

      fStatusMap = mapMaker.MakePadStatusMap(*status,mask);

      delete status;
    }
    else
    {
      // make a fake (empty) status map
      fStatusMap = AliMUONPadStatusMapMaker::MakeEmptyPadStatusMap();
    }
}

//_____________________________________________________________________________
AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
{
  /// dtor.
  delete fStatusMap;

  AliInfo("Summary of messages:");
  fLogger->Print();

  delete fLogger;
}

//_____________________________________________________________________________
void
AliMUONDigitCalibrator::Exec(Option_t*)
{
  /// Main method.
  /// We loop on tracking chambers (i.e. we do nothing for trigger)
  /// and for each digit in that chamber, we calibrate it :
  /// a) we set its status map and if status is bad, set the signal to zero
  /// b) we then apply pedestal and gain corrections.

  for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ++ch )
  {
    TClonesArray* digitArray = fData->Digits(ch);
    Int_t nDigits = digitArray->GetEntriesFast();
    for ( Int_t d = 0; d < nDigits; ++d )
    {
      AliMUONDigit* digit =
        static_cast<AliMUONDigit*>(digitArray->UncheckedAt(d));

      AliMUONVCalibParam* deadmap = static_cast<AliMUONVCalibParam*>
        (fStatusMap->Get(digit->DetElemId(),digit->ManuId()));
      Int_t statusMap = deadmap->ValueAsInt(digit->ManuChannel());
      digit->SetStatusMap(statusMap);
      if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 ) // pad itself is bad (not testing its neighbours at this stage)
      {
        digit->SetSignal(0);
        fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
                        "manuChannel %d is bad %x",__FILE__,__LINE__,
                          digit->DetElemId(),digit->ManuId(),
                        digit->ManuChannel(),digit->StatusMap()));
        continue;
      }

      // If the channel is good, go on with the calibration itself.

      AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
        (fCalibrationData->Pedestals(digit->DetElemId(),digit->ManuId()));

      AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
        (fCalibrationData->Gains(digit->DetElemId(),digit->ManuId()));

      if (!pedestal)
      {
        AliFatal(Form("Got a null ped object for DE,manu=%d,%d",
                      digit->DetElemId(),digit->ManuId()));

      }
      if (!gain)
      {
        AliFatal(Form("Got a null gain object for DE,manu=%d,%d",
                      digit->DetElemId(),digit->ManuId()));
      }

      Int_t manuChannel = digit->ManuChannel();
      Float_t adc = digit->Signal();
      Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
      if ( padc < 3.0*pedestal->ValueAsFloat(manuChannel,1) )
      {
        padc = 0.0;
      }
      Float_t charge = padc*gain->ValueAsFloat(manuChannel,0);
      digit->SetSignal(charge);
      Int_t saturation = gain->ValueAsInt(manuChannel,1);
      if ( charge >= saturation )
      {
        digit->Saturated(kTRUE);
      }
    }
  }
}
<commit_msg>Updated for modifs in AliMUONPadStatusMapMaker (Laurent)<commit_after>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONDigitCalibrator.h"

#include "AliLog.h"
#include "AliMUONCalibrationData.h"
#include "AliMUONConstants.h"
#include "AliMUONData.h"
#include "AliMUONDigit.h"
#include "AliMUONLogger.h"
#include "AliMUONPadStatusMaker.h"
#include "AliMUONPadStatusMapMaker.h"
#include "AliMUONV2DStore.h"
#include "AliMUONVCalibParam.h"
#include "TClonesArray.h"

/// \class AliMUONDigitCalibrator
/// Class used to calibrate digits (either real or simulated ones).
///
/// The calibration consists of subtracting the pedestal
/// and multiplying by a gain, so that
/// Signal = (ADC-pedestal)*gain
///
/// Please note also that for the moment, if a digit lies on a dead channel
/// we remove this digit from the list of digits.
/// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
/// should in principle flag a digit as bad w/o removing it, but this
/// then requires some changes in the cluster finder to deal with this extra
/// information correctly (e.g. to set a quality for the cluster if it contains
/// bad digits).
///
/// \author Laurent Aphecetche

/// \cond CLASSIMP
ClassImp(AliMUONDigitCalibrator)
/// \endcond

//_____________________________________________________________________________
AliMUONDigitCalibrator::AliMUONDigitCalibrator(AliMUONData* muonData,
                                               AliMUONCalibrationData* calib,
                                               Bool_t createAndUseStatusMap)
: TTask("AliMUONDigitCalibrator","Raw digit calibration"),
  fData(muonData),
  fCalibrationData(calib),
  fStatusMap(0x0),
  fLogger(new AliMUONLogger(1000))
{
    /// ctor. This class needs the muonData to get access to the digit,
    /// and the calibrationData to get access to calibration parameters.

    if (!calib) {
      AliFatal("No calibration data defined");
    }

    if (createAndUseStatusMap)
    {
      AliMUONPadStatusMaker maker(*calib);

      // this is here that we decide on our "goodness" policy, i.e.
      // what do we call an invalid pad (a pad maybe bad because its HV
      // was too low, or its pedestals too high, etc..)
      //
      maker.SetHVSt12Limits(1300,1600);
      maker.SetHVSt345Limits(1500,2000);
      maker.SetPedMeanLimits(50,200);
      maker.SetPedSigmaLimits(0.1,3);

      // From this set of limits, compute the status of all tracker pads.
      AliMUONV2DStore* status = maker.MakeStatus();
      // we do not check that status is != 0x0, as this is supposed to be
      // the responsability of the padStatusMaker.

      AliMUONPadStatusMapMaker mapMaker(*calib);

      Int_t mask(0x8080);
      //FIXME: kind of fake one for the moment, we consider dead only
      // if ped and/or hv value missing.
      //WARNING : getting this mask wrong is a very effective way of getting
      //no digits at all out of this class ;-)

      fStatusMap = mapMaker.MakePadStatusMap(*status,mask);

      delete status;
    }
    else
    {
      // make a fake (empty) status map
      fStatusMap = AliMUONPadStatusMapMaker::MakeEmptyPadStatusMap();
    }
}

//_____________________________________________________________________________
AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
{
  /// dtor.
  delete fStatusMap;

  AliInfo("Summary of messages:");
  fLogger->Print();

  delete fLogger;
}

//_____________________________________________________________________________
void
AliMUONDigitCalibrator::Exec(Option_t*)
{
  /// Main method.
  /// We loop on tracking chambers (i.e. we do nothing for trigger)
  /// and for each digit in that chamber, we calibrate it :
  /// a) we set its status map and if status is bad, set the signal to zero
  /// b) we then apply pedestal and gain corrections.

  for ( Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ++ch )
  {
    TClonesArray* digitArray = fData->Digits(ch);
    Int_t nDigits = digitArray->GetEntriesFast();
    for ( Int_t d = 0; d < nDigits; ++d )
    {
      AliMUONDigit* digit =
        static_cast<AliMUONDigit*>(digitArray->UncheckedAt(d));

      AliMUONVCalibParam* deadmap = static_cast<AliMUONVCalibParam*>
        (fStatusMap->Get(digit->DetElemId(),digit->ManuId()));
      Int_t statusMap = deadmap->ValueAsInt(digit->ManuChannel());
      digit->SetStatusMap(statusMap);
      if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 ) // pad itself is bad (not testing its neighbours at this stage)
      {
        digit->SetSignal(0);
        fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
                        "manuChannel %d is bad %x",__FILE__,__LINE__,
                          digit->DetElemId(),digit->ManuId(),
                        digit->ManuChannel(),digit->StatusMap()));
        continue;
      }

      // If the channel is good, go on with the calibration itself.

      AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
        (fCalibrationData->Pedestals(digit->DetElemId(),digit->ManuId()));

      AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
        (fCalibrationData->Gains(digit->DetElemId(),digit->ManuId()));

      if (!pedestal)
      {
        AliFatal(Form("Got a null ped object for DE,manu=%d,%d",
                      digit->DetElemId(),digit->ManuId()));

      }
      if (!gain)
      {
        AliFatal(Form("Got a null gain object for DE,manu=%d,%d",
                      digit->DetElemId(),digit->ManuId()));
      }

      Int_t manuChannel = digit->ManuChannel();
      Float_t adc = digit->Signal();
      Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
      if ( padc < 3.0*pedestal->ValueAsFloat(manuChannel,1) )
      {
        padc = 0.0;
      }
      Float_t charge = padc*gain->ValueAsFloat(manuChannel,0);
      digit->SetSignal(charge);
      Int_t saturation = gain->ValueAsInt(manuChannel,1);
      if ( charge >= saturation )
      {
        digit->Saturated(kTRUE);
      }
    }
  }
}
<|endoftext|>