<commit_before>#include "kwm.h"
#include "helpers.h"
#include "daemon.h"
#include "display.h"
#include "space.h"
#include "window.h"
#include "keys.h"
#include "interpreter.h"
#include "scratchpad.h"
#include "border.h"
#include "config.h"
#include "cursor.h"
#include "axlib/axlib.h"
#include <getopt.h>

#define internal static
const std::string KwmCurrentVersion = "Kwm Version 3.0.7";
std::map<std::string, space_info> WindowTree;

ax_state AXState = {};
ax_display *FocusedDisplay = NULL;
ax_application *FocusedApplication = NULL;
ax_window *MarkedWindow = NULL;

kwm_mach KWMMach = {};
kwm_path KWMPath = {};
kwm_settings KWMSettings = {};
kwm_thread KWMThread = {};
kwm_hotkeys KWMHotkeys = {};
kwm_border FocusedBorder = {};
kwm_border MarkedBorder = {};
scratchpad Scratchpad = {};

internal CGEventRef
CGEventCallback(CGEventTapProxy Proxy, CGEventType Type, CGEventRef Event, void *Refcon)
{
    switch(Type)
    {
        case kCGEventTapDisabledByTimeout:
        case kCGEventTapDisabledByUserInput:
        {
            DEBUG("Notice: Restarting Event Tap");
            CGEventTapEnable(KWMMach.EventTap, true);
        } break;
        case kCGEventKeyDown:
        {
            /* TODO(koekeishiya): Is there a better way to decide whether
                                  we should eat the CGEventRef or not (?) */
            if(HasFlags(&KWMSettings, Settings_BuiltinHotkeys))
            {
                hotkey Eventkey = {}, *Hotkey = NULL;
                Hotkey = new hotkey;
                if(Hotkey)
                {
                    CreateHotkeyFromCGEvent(Event, &Eventkey);
                    if(HotkeyExists(Eventkey.Flags, Eventkey.Key, Hotkey, KWMHotkeys.ActiveMode->Name))
                    {
                        AXLibConstructEvent(AXEvent_HotkeyPressed, Hotkey, false);
                        if(!(Hotkey->Flags & Hotkey_Modifier_Flag_Passthrough))
                            return NULL;
                    }
                    else
                    {
                        delete Hotkey;
                    }
                }
            }
        } break;
        case kCGEventMouseMoved:
        {
            if(KWMSettings.Focus == FocusModeAutoraise)
                AXLibConstructEvent(AXEvent_MouseMoved, NULL, false);
        } break;
        default: {} break;
    }

    return Event;
}

internal bool
CheckPrivileges()
{
    bool Result = false;
    const void * Keys[] = { kAXTrustedCheckOptionPrompt };
    const void * Values[] = { kCFBooleanTrue };

    CFDictionaryRef Options;
    Options = CFDictionaryCreate(kCFAllocatorDefault,
                                 Keys, Values, sizeof(Keys) / sizeof(*Keys),
                                 &kCFCopyStringDictionaryKeyCallBacks,
                                 &kCFTypeDictionaryValueCallBacks);

    Result = AXIsProcessTrustedWithOptions(Options);
    CFRelease(Options);

    return Result;
}

internal bool
GetKwmFilePath()
{
    bool Result = false;
    char PathBuf[PROC_PIDPATHINFO_MAXSIZE];
    pid_t Pid = getpid();
    int Ret = proc_pidpath(Pid, PathBuf, sizeof(PathBuf));
    if (Ret > 0)
    {
        KWMPath.FilePath = PathBuf;

        std::size_t Split = KWMPath.FilePath.find_last_of("/\\");
        KWMPath.FilePath = KWMPath.FilePath.substr(0, Split);
        Result = true;
    }

    return Result;
}

internal void
KwmClearSettings()
{
    KWMHotkeys.Modes.clear();
    KWMSettings.WindowRules.clear();
    KWMSettings.SpaceSettings.clear();
    KWMSettings.DisplaySettings.clear();
    KWMHotkeys.ActiveMode = GetBindingMode("default");
}

internal void
KwmExecuteInitScript()
{
    if(KWMPath.Init.empty())
        KWMPath.Init = KWMPath.Home + "/init";

    struct stat Buffer;
    if(stat(KWMPath.Init.c_str(), &Buffer) == 0)
        KwmExecuteSystemCommand(KWMPath.Init);
}

internal void
SignalHandler(int Signum)
{
    ShowAllScratchpadWindows();
    DEBUG("SignalHandler() " << Signum);

    CloseBorder(&FocusedBorder);
    CloseBorder(&MarkedBorder);
    exit(Signum);
}

internal void
Fatal(const std::string &Err)
{
    std::cout << Err << std::endl;
    exit(1);
}

internal void
KwmInit()
{
    if(!CheckPrivileges())
        Fatal("Error: Could not access OSX Accessibility!");

    if(KwmStartDaemon())
        pthread_create(&KWMThread.Daemon, NULL, &KwmDaemonHandleConnectionBG, NULL);
    else
        Fatal("Error: Could not start daemon!");

#ifndef DEBUG_BUILD
    signal(SIGSEGV, SignalHandler);
    signal(SIGABRT, SignalHandler);
    signal(SIGTRAP, SignalHandler);
    signal(SIGTERM, SignalHandler);
    signal(SIGKILL, SignalHandler);
    signal(SIGINT, SignalHandler);
#else
    printf("Notice: Signal handlers disabled!\n");
#endif

    KWMSettings.SplitRatio = 0.5;
    KWMSettings.SplitMode = SPLIT_OPTIMAL;
    KWMSettings.DefaultOffset = CreateDefaultScreenOffset();
    KWMSettings.OptimalRatio = 1.618;

    AddFlags(&KWMSettings,
            Settings_MouseFollowsFocus |
            Settings_BuiltinHotkeys |
            Settings_StandbyOnFloat |
            Settings_CenterOnFloat |
            Settings_LockToContainer);

    KWMSettings.Space = SpaceModeBSP;
    KWMSettings.Focus = FocusModeAutoraise;
    KWMSettings.Cycle = CycleModeScreen;

    FocusedBorder.Radius = -1;
    FocusedBorder.Type = BORDER_FOCUSED;
    MarkedBorder.Radius = -1;
    MarkedBorder.Type = BORDER_MARKED;

    char *HomeP = std::getenv("HOME");
    if(HomeP)
    {
        KWMPath.EnvHome = HomeP;
        KWMPath.Home = KWMPath.EnvHome + "/.kwm";
        KWMPath.Include = KWMPath.Home;
        KWMPath.Layouts = KWMPath.Home + "/layouts";

        if(KWMPath.Config.empty())
            KWMPath.Config = KWMPath.Home + "/kwmrc";
    }
    else
    {
        Fatal("Error: Failed to get environment variable 'HOME'");
    }

    KWMHotkeys.ActiveMode = GetBindingMode("default");
    GetKwmFilePath();
}

void KwmQuit()
{
    ShowAllScratchpadWindows();
    CloseBorder(&FocusedBorder);
    CloseBorder(&MarkedBorder);

    exit(0);
}

void KwmReloadConfig()
{
    KwmClearSettings();
    KwmParseConfig(KWMPath.Config);
}

/* NOTE(koekeishiya): Returns true for operations that cause Kwm to exit. */
internal bool
ParseArguments(int argc, char **argv)
{
    int Option;
    const char *ShortOptions = "vc:";
    struct option LongOptions[] =
    {
        {"version", no_argument, NULL, 'v'},
        {"config", required_argument, NULL, 'c'},
        {NULL, 0, NULL, 0}
    };

    while((Option = getopt_long(argc, argv, ShortOptions, LongOptions, NULL)) != -1)
    {
        switch(Option)
        {
            case 'v':
            {
                printf("%s\n", KwmCurrentVersion.c_str());
                return true;
            } break;
            case 'c':
            {
                DEBUG("Notice: Using config file " << optarg);
                KWMPath.Config = optarg;
            } break;
        }
    }

    return false;
}

internal inline void
ConfigureRunLoop()
{
    KWMMach.EventMask = ((1 << kCGEventKeyDown) |
                         (1 << kCGEventMouseMoved));

    KWMMach.EventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, KWMMach.EventMask, CGEventCallback, NULL);
    if(!KWMMach.EventTap || !CGEventTapIsEnabled(KWMMach.EventTap))
        Fatal("Error: Could not create event-tap!");

    CFRunLoopAddSource(CFRunLoopGetMain(),
                       CFMachPortCreateRunLoopSource(kCFAllocatorDefault, KWMMach.EventTap, 0),
                       kCFRunLoopCommonModes);
}

int main(int argc, char **argv)
{
    if(ParseArguments(argc, argv))
        return 0;

    NSApplicationLoad();
    if(!AXLibDisplayHasSeparateSpaces())
        Fatal("Error: 'Displays have separate spaces' must be enabled!");

    AXLibInit(&AXState);
    AXLibStartEventLoop();

    ax_display *MainDisplay = AXLibMainDisplay();
    ax_display *Display = MainDisplay;
    do
    {
        ax_space *PrevSpace = Display->Space;
        Display->Space = AXLibGetActiveSpace(Display);
        Display->PrevSpace = PrevSpace;
        Display = AXLibNextDisplay(Display);
    } while(Display != MainDisplay);

    FocusedDisplay = MainDisplay;
    FocusedApplication = AXLibGetFocusedApplication();

    KwmInit();
    KwmParseConfig(KWMPath.Config);
    KwmExecuteInitScript();

    CreateWindowNodeTree(MainDisplay);
    UpdateBorder(&FocusedBorder, FocusedApplication->Focus);

    if(CGSIsSecureEventInputSet())
        fprintf(stderr, "Notice: Secure Keyboard Entry is enabled, hotkeys will not work!\n");

    ConfigureRunLoop();
    CFRunLoopRun();
    return 0;
}
<commit_msg>properly reap processes<commit_after>#include "kwm.h"
#include "helpers.h"
#include "daemon.h"
#include "display.h"
#include "space.h"
#include "window.h"
#include "keys.h"
#include "interpreter.h"
#include "scratchpad.h"
#include "border.h"
#include "config.h"
#include "cursor.h"
#include "axlib/axlib.h"
#include <getopt.h>

#define internal static
const std::string KwmCurrentVersion = "Kwm Version 3.0.7";
std::map<std::string, space_info> WindowTree;

ax_state AXState = {};
ax_display *FocusedDisplay = NULL;
ax_application *FocusedApplication = NULL;
ax_window *MarkedWindow = NULL;

kwm_mach KWMMach = {};
kwm_path KWMPath = {};
kwm_settings KWMSettings = {};
kwm_thread KWMThread = {};
kwm_hotkeys KWMHotkeys = {};
kwm_border FocusedBorder = {};
kwm_border MarkedBorder = {};
scratchpad Scratchpad = {};

internal CGEventRef
CGEventCallback(CGEventTapProxy Proxy, CGEventType Type, CGEventRef Event, void *Refcon)
{
    switch(Type)
    {
        case kCGEventTapDisabledByTimeout:
        case kCGEventTapDisabledByUserInput:
        {
            DEBUG("Notice: Restarting Event Tap");
            CGEventTapEnable(KWMMach.EventTap, true);
        } break;
        case kCGEventKeyDown:
        {
            /* TODO(koekeishiya): Is there a better way to decide whether
                                  we should eat the CGEventRef or not (?) */
            if(HasFlags(&KWMSettings, Settings_BuiltinHotkeys))
            {
                hotkey Eventkey = {}, *Hotkey = NULL;
                Hotkey = new hotkey;
                if(Hotkey)
                {
                    CreateHotkeyFromCGEvent(Event, &Eventkey);
                    if(HotkeyExists(Eventkey.Flags, Eventkey.Key, Hotkey, KWMHotkeys.ActiveMode->Name))
                    {
                        AXLibConstructEvent(AXEvent_HotkeyPressed, Hotkey, false);
                        if(!(Hotkey->Flags & Hotkey_Modifier_Flag_Passthrough))
                            return NULL;
                    }
                    else
                    {
                        delete Hotkey;
                    }
                }
            }
        } break;
        case kCGEventMouseMoved:
        {
            if(KWMSettings.Focus == FocusModeAutoraise)
                AXLibConstructEvent(AXEvent_MouseMoved, NULL, false);
        } break;
        default: {} break;
    }

    return Event;
}

internal bool
CheckPrivileges()
{
    bool Result = false;
    const void * Keys[] = { kAXTrustedCheckOptionPrompt };
    const void * Values[] = { kCFBooleanTrue };

    CFDictionaryRef Options;
    Options = CFDictionaryCreate(kCFAllocatorDefault,
                                 Keys, Values, sizeof(Keys) / sizeof(*Keys),
                                 &kCFCopyStringDictionaryKeyCallBacks,
                                 &kCFTypeDictionaryValueCallBacks);

    Result = AXIsProcessTrustedWithOptions(Options);
    CFRelease(Options);

    return Result;
}

internal bool
GetKwmFilePath()
{
    bool Result = false;
    char PathBuf[PROC_PIDPATHINFO_MAXSIZE];
    pid_t Pid = getpid();
    int Ret = proc_pidpath(Pid, PathBuf, sizeof(PathBuf));
    if (Ret > 0)
    {
        KWMPath.FilePath = PathBuf;

        std::size_t Split = KWMPath.FilePath.find_last_of("/\\");
        KWMPath.FilePath = KWMPath.FilePath.substr(0, Split);
        Result = true;
    }

    return Result;
}

internal void
KwmClearSettings()
{
    KWMHotkeys.Modes.clear();
    KWMSettings.WindowRules.clear();
    KWMSettings.SpaceSettings.clear();
    KWMSettings.DisplaySettings.clear();
    KWMHotkeys.ActiveMode = GetBindingMode("default");
}

internal void
KwmExecuteInitScript()
{
    if(KWMPath.Init.empty())
        KWMPath.Init = KWMPath.Home + "/init";

    struct stat Buffer;
    if(stat(KWMPath.Init.c_str(), &Buffer) == 0)
        KwmExecuteSystemCommand(KWMPath.Init);
}

internal void
SignalHandler(int Signum)
{
    ShowAllScratchpadWindows();
    DEBUG("SignalHandler() " << Signum);

    CloseBorder(&FocusedBorder);
    CloseBorder(&MarkedBorder);
    exit(Signum);
}

internal void
Fatal(const std::string &Err)
{
    std::cout << Err << std::endl;
    exit(1);
}

internal void
KwmInit()
{
    if(!CheckPrivileges())
        Fatal("Error: Could not access OSX Accessibility!");

    if(KwmStartDaemon())
        pthread_create(&KWMThread.Daemon, NULL, &KwmDaemonHandleConnectionBG, NULL);
    else
        Fatal("Error: Could not start daemon!");

    signal(SIGCHLD, SIG_IGN);
#ifndef DEBUG_BUILD
    signal(SIGSEGV, SignalHandler);
    signal(SIGABRT, SignalHandler);
    signal(SIGTRAP, SignalHandler);
    signal(SIGTERM, SignalHandler);
    signal(SIGKILL, SignalHandler);
    signal(SIGINT, SignalHandler);
#else
    printf("Notice: Signal handlers disabled!\n");
#endif

    KWMSettings.SplitRatio = 0.5;
    KWMSettings.SplitMode = SPLIT_OPTIMAL;
    KWMSettings.DefaultOffset = CreateDefaultScreenOffset();
    KWMSettings.OptimalRatio = 1.618;

    AddFlags(&KWMSettings,
            Settings_MouseFollowsFocus |
            Settings_BuiltinHotkeys |
            Settings_StandbyOnFloat |
            Settings_CenterOnFloat |
            Settings_LockToContainer);

    KWMSettings.Space = SpaceModeBSP;
    KWMSettings.Focus = FocusModeAutoraise;
    KWMSettings.Cycle = CycleModeScreen;

    FocusedBorder.Radius = -1;
    FocusedBorder.Type = BORDER_FOCUSED;
    MarkedBorder.Radius = -1;
    MarkedBorder.Type = BORDER_MARKED;

    char *HomeP = std::getenv("HOME");
    if(HomeP)
    {
        KWMPath.EnvHome = HomeP;
        KWMPath.Home = KWMPath.EnvHome + "/.kwm";
        KWMPath.Include = KWMPath.Home;
        KWMPath.Layouts = KWMPath.Home + "/layouts";

        if(KWMPath.Config.empty())
            KWMPath.Config = KWMPath.Home + "/kwmrc";
    }
    else
    {
        Fatal("Error: Failed to get environment variable 'HOME'");
    }

    KWMHotkeys.ActiveMode = GetBindingMode("default");
    GetKwmFilePath();
}

void KwmQuit()
{
    ShowAllScratchpadWindows();
    CloseBorder(&FocusedBorder);
    CloseBorder(&MarkedBorder);

    exit(0);
}

void KwmReloadConfig()
{
    KwmClearSettings();
    KwmParseConfig(KWMPath.Config);
}

/* NOTE(koekeishiya): Returns true for operations that cause Kwm to exit. */
internal bool
ParseArguments(int argc, char **argv)
{
    int Option;
    const char *ShortOptions = "vc:";
    struct option LongOptions[] =
    {
        {"version", no_argument, NULL, 'v'},
        {"config", required_argument, NULL, 'c'},
        {NULL, 0, NULL, 0}
    };

    while((Option = getopt_long(argc, argv, ShortOptions, LongOptions, NULL)) != -1)
    {
        switch(Option)
        {
            case 'v':
            {
                printf("%s\n", KwmCurrentVersion.c_str());
                return true;
            } break;
            case 'c':
            {
                DEBUG("Notice: Using config file " << optarg);
                KWMPath.Config = optarg;
            } break;
        }
    }

    return false;
}

internal inline void
ConfigureRunLoop()
{
    KWMMach.EventMask = ((1 << kCGEventKeyDown) |
                         (1 << kCGEventMouseMoved));

    KWMMach.EventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, KWMMach.EventMask, CGEventCallback, NULL);
    if(!KWMMach.EventTap || !CGEventTapIsEnabled(KWMMach.EventTap))
        Fatal("Error: Could not create event-tap!");

    CFRunLoopAddSource(CFRunLoopGetMain(),
                       CFMachPortCreateRunLoopSource(kCFAllocatorDefault, KWMMach.EventTap, 0),
                       kCFRunLoopCommonModes);
}

int main(int argc, char **argv)
{
    if(ParseArguments(argc, argv))
        return 0;

    NSApplicationLoad();
    if(!AXLibDisplayHasSeparateSpaces())
        Fatal("Error: 'Displays have separate spaces' must be enabled!");

    AXLibInit(&AXState);
    AXLibStartEventLoop();

    ax_display *MainDisplay = AXLibMainDisplay();
    ax_display *Display = MainDisplay;
    do
    {
        ax_space *PrevSpace = Display->Space;
        Display->Space = AXLibGetActiveSpace(Display);
        Display->PrevSpace = PrevSpace;
        Display = AXLibNextDisplay(Display);
    } while(Display != MainDisplay);

    FocusedDisplay = MainDisplay;
    FocusedApplication = AXLibGetFocusedApplication();

    KwmInit();
    KwmParseConfig(KWMPath.Config);
    KwmExecuteInitScript();

    CreateWindowNodeTree(MainDisplay);
    UpdateBorder(&FocusedBorder, FocusedApplication->Focus);

    if(CGSIsSecureEventInputSet())
        fprintf(stderr, "Notice: Secure Keyboard Entry is enabled, hotkeys will not work!\n");

    ConfigureRunLoop();
    CFRunLoopRun();
    return 0;
}
<|endoftext|>


<commit_before>#include <TCanvas.h>
//#include <TLegend.h>
//#include <TRandom3.h>
#include "TH1.h"
//#include "TF1.h"
//#include "TMath.h"
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

class hit
{
	public:

	double x;
	double y;

	//vector<hit> cluster;

	hit(double x, double y): x(x), y(y) {}

	double distance_from(hit h)
	{
		double Dx2 = pow((this->x - h.x), 2);
		double Dy2 = pow((this->y - h.y), 2);
		return sqrt(Dx2 + Dy2);
	}

	bool is_inside(double xmax, double ymax) {
		return (abs(x)<=xmax && abs(y)<=ymax);
	}
};

class eeevent
{
	int num1;

	int num_trig;
	int num_acq;

	int secs;
	int nsecs;

	int clk1;
	int clk2;

	double hv1;
	double hv2;
	double hv3;

	public:

	vector<hit> hits [3];  // array of vector of hit

	eeevent(int num1, int num_trig, int num_acq, int secs, int nsecs, int clk1, int clk2, double hv1, double hv2, double hv3):
		num1(num1), num_trig(num_trig), num_acq(num_acq), secs(secs), nsecs(nsecs),
		clk1(clk1), clk2(clk2), hv1(hv1), hv2(hv2), hv3(hv3) {}

	void gethit(double x, double y, int z) {
		hit newhit(x, y);
		switch (z) {
			case 149:
				this->hits[0].push_back(newhit);
				break;
			case 95:
				this->hits[1].push_back(newhit);
				break;
			case 49:
				this->hits[2].push_back(newhit);
				break;
			default:
				cout << "Unrecognized chamber" << endl;
		}
	}
};

typedef vector<eeevent> eeevector;
typedef vector<hit> hitvector;

vector<eeevent> parse(string path)
{
	cout << "Path given: " << path << endl;

	ifstream file;
	file.open(path);
	if (file==NULL) {
		cout << "File does not exist" << endl;
		exit(1);
	}
	const int linesize=65536;
	char* line = (char*)malloc(linesize*sizeof(char));  // get buffer for every line

	vector<eeevent> evector;               // vector for the events
	double hv1, hv2, hv3;                  // variables for high voltage values

	while (!file.eof()) {
		file.getline(line, linesize);       // fill line

		char* piece = strtok (line," \t");  // get initial number
		if (piece==NULL) continue;          // the file is finished at this point, but better run the eof() check
		int num1 = atoi(piece);             // inital number
		if (num1 == 0) continue;            // line needs to start with a number, not characters (like the name line)

		piece = strtok (NULL, " \t");       // get descriptor
		string descriptor = piece;

		if (descriptor=="STATUS") {
			char* next=piece+7;              // hack to get after "STATUS"
			sscanf(next, "HV %lf %*f %lf %*f %lf %*f", &hv1, &hv2, &hv3);
			//cout << "hv: " << hv1 << " - " << hv2 << " - " << hv3 << endl;
		}
		else if (descriptor=="EVENT") {

			piece = strtok (NULL, " \t");    // get num_trig
			int num_trig = atoi(piece);

			piece = strtok (NULL, " \t");    // get num_acq
			int num_acq = atoi(piece);

			piece = strtok (NULL, " \t");    // get seconds
			int secs = atoi(piece);

			piece = strtok (NULL, " \t");    // get nseconds
			int nsecs = atoi(piece);

			piece = strtok (NULL, " \t");    // get clk1
			int clk1 = atoi(piece);

			piece = strtok (NULL, " \t");    // get clk2
			int clk2 = atoi(piece);

			eeevent neweeevent(num1, num_trig, num_acq, secs, nsecs, clk1, clk2, hv1, hv2, hv3);

			piece = strtok (NULL, " \t");    // get events
			while (piece != NULL) {
				double x = atof(piece);
				piece = strtok (NULL, " \t");    // get more pieces

				if (piece!=NULL) {
					double y = atof(piece);
					piece = strtok (NULL, " \t");    // get more pieces

					int z = atoi(piece);
					piece = strtok (NULL, " \t");    // get more pieces

					neweeevent.gethit(x, y, z);
					//cout << x << " - " << y << " - " << z << endl;
				}
			}

			evector.push_back(neweeevent);
		}
	}
	cout << "Parsing completed: " << evector.size() << " events captured" << endl << endl;

	return evector;
}

void cluster_size_study(eeevector evector)
{
	const double step = 0.01;
	const double maxradius = 20;

	// Create the canvas
	TCanvas *canv = new TCanvas("canvas","canvas title", 800, 600);
	canv->cd();
	TH1D *hist = new TH1D("", "Cluster", maxradius/step-1, 0, maxradius);

	for (size_t i=0; i<evector.size(); ++i) {              // for every event
		eeevent event1 = evector[i];
		for (int ch=0; ch<3; ++ch) {                        // for every chamber
			if (event1.hits[ch].size() > 1) {                      // if there are hits in ch
				for (size_t j=0; j<event1.hits[ch].size(); ++j) {   // for every hit in ch
					hit hit1 = event1.hits[ch][j];
					for (size_t k=j+1; k<event1.hits[ch].size(); ++k) {   // for every other hit in ch
						hit hit2 = event1.hits[ch][k];
						double dist = hit2.distance_from(hit1);
						for (double radius=maxradius; radius > dist; radius-=step) {   // for every radius
							hist->Fill(radius);
						}
					}
				}
			}
		}
	}
	hist->SetStats(kFALSE);
	hist->Draw();
	cout << "Done clusters" << endl << endl;
}

void chamber_assign(int chtest, int* ch1, int* ch2)
{
	switch (chtest) {
		case 0: *ch1 = 1; *ch2 = 2; break;
		case 1: *ch1 = 0; *ch2 = 2; break;
		case 2: *ch1 = 0; *ch2 = 1; break;
		default: cout << "Unrecognized chamber" << endl;
	}
}

hit compute_hitpoint(int chtest, hit hit1, hit hit2)
{
	double z, z1, z2;
	switch (chtest) {
		case 0: z = 149.00; z1 =  95.50; z2 =  49.00; break;
		case 1: z =  95.50; z1 = 149.00; z2 =  49.00; break;
		case 2: z =  49.00; z1 = 149.00; z2 =  95.50; break;
		default: cout << "Unrecognized chamber" << endl; exit(1);
	}
	// line equation is: (x-x1)/(x2-x1)=(y-y1)/(y2-y1)=(z-z1)/(z2-z1)=A

	double x1 = hit1.x;
	double x2 = hit2.x;
	double y1 = hit1.y;
	double y2 = hit2.y;

	double A = (z-z1)/(z2-z1);
	double x = (x2-x1)*A +x1;
	double y = (y2-y1)*A +y1;
	return {x, y};
}

void compute_eff(int chtest, eeevector evector)
{
	const double xmax=2000;
	const double ymax=2000;
	const double dist_cutoff=10;

	int expected=0;
	int detected=0;

	int ch1, ch2;
	chamber_assign(chtest, &ch1, &ch2);

	for (size_t i=0; i<evector.size(); ++i) {              // for every event
		eeevent event1 = evector[i];
		for (size_t j=0; j<event1.hits[ch1].size(); ++j) {   // for every hit in ch1
			hit hit1 = event1.hits[ch1][j];
			for (size_t k=0; k<event1.hits[ch2].size(); ++k) {   // for every hit in ch2
				hit hit2 = event1.hits[ch2][k];
				hit hit_test = compute_hitpoint(chtest, hit1, hit2);
				if (hit_test.is_inside(xmax, ymax)) {
					expected++;
					for (size_t h=0; h<event1.hits[chtest].size(); ++h) {   // for every hit in chtest
						hit hitf = event1.hits[chtest][h];
						double dist = hit_test.distance_from(hitf);
						if (dist < dist_cutoff) {
							detected++;
							break;
						}
					}
				}
			}
		}
	}
	cout << "Distance cutoff chosen: " << dist_cutoff << endl;
	cout << "Expected events: " << expected << endl;
	cout << "Detected events: " << detected << endl;
	cout << "Efficiency: " << (double)detected/expected << endl << endl;

}

int parser(string path)
{

	eeevector evector;
	evector = parse(path);

	//cluster_size_study(evector);
	//evector = clusterize(evector, cluster_size);

	compute_eff(1, evector);

	return 0;
}

int main(int, char** argv)
{
	string path = argv[1];
	parser(path);

	return 0;
}

/* Code graveyard
*
*
*
	hitvector hvector;
	switch (nchamber) {
		case 1: hvector=evector.hits1; break;
		case 2: hvector=evector.hits2; break;
		case 3: hvector=evector.hits3; break;
		default: cout << "Unexpected chamber number" << endl;
	}
*
	if (dist < radius) {
		if (hit1.cluster.size() == 0 && hit1.cluster.size() == 0) counter++;
		hit1.cluster.push_back(hit2);
		hit2.cluster.push_back(hit1);
	}
*
*
*/
<commit_msg>Some more progress on parser<commit_after>#include <TCanvas.h>
//#include <TLegend.h>
//#include <TRandom3.h>
#include "TH1.h"
#include "TH2.h"
//#include "TF1.h"
//#include "TMath.h"
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

class hit
{
	public:

	double x;
	double y;

	//vector<hit> cluster;

	hit(double x, double y): x(x), y(y) {}

	double distance_from(hit h)
	{
		double Dx2 = pow((this->x - h.x), 2);
		double Dy2 = pow((this->y - h.y), 2);
		return sqrt(Dx2 + Dy2);
	}

	bool is_inside(double xmax, double ymax) {
		return (abs(x)<=xmax && abs(y)<=ymax);
	}
};

class eeevent
{
	int num1;

	int num_trig;
	int num_acq;

	int secs;
	int nsecs;

	int clk1;
	int clk2;

	double hv1;
	double hv2;
	double hv3;

	public:

	vector<hit> hits [3];  // array of vector of hit

	eeevent(int num1, int num_trig, int num_acq, int secs, int nsecs, int clk1, int clk2, double hv1, double hv2, double hv3):
		num1(num1), num_trig(num_trig), num_acq(num_acq), secs(secs), nsecs(nsecs),
		clk1(clk1), clk2(clk2), hv1(hv1), hv2(hv2), hv3(hv3) {}

	void gethit(double x, double y, int z) {
		hit newhit(x, y);
		switch (z) {
			case 149:
				this->hits[0].push_back(newhit);
				break;
			case 95:
				this->hits[1].push_back(newhit);
				break;
			case 49:
				this->hits[2].push_back(newhit);
				break;
			default:
				cout << "Unrecognized chamber" << endl;
		}
	}
};

typedef vector<eeevent> eeevector;
typedef vector<hit> hitvector;

eeevector parse(string path)
{
	cout << "Path given: " << path << endl;

	ifstream file;
	file.open(path);
	if (file==NULL) {
		cout << "File does not exist" << endl;
		exit(1);
	}
	const int linesize=65536;
	char* line = (char*)malloc(linesize*sizeof(char));  // get buffer for every line

	vector<eeevent> evector;               // vector for the events
	double hv1, hv2, hv3;                  // variables for high voltage values

	while (!file.eof()) {
		file.getline(line, linesize);       // fill line

		char* piece = strtok (line," \t");  // get initial number
		if (piece==NULL) continue;          // the file is finished at this point, but better run the eof() check
		int num1 = atoi(piece);             // inital number
		if (num1 == 0) continue;            // line needs to start with a number, not characters (like the name line)

		piece = strtok (NULL, " \t");       // get descriptor
		string descriptor = piece;

		if (descriptor=="STATUS") {
			char* next=piece+7;              // hack to get after "STATUS"
			sscanf(next, "HV %lf %*f %lf %*f %lf %*f", &hv1, &hv2, &hv3);
			//cout << "hv: " << hv1 << " - " << hv2 << " - " << hv3 << endl;
		}
		else if (descriptor=="EVENT") {

			piece = strtok (NULL, " \t");    // get num_trig
			int num_trig = atoi(piece);

			piece = strtok (NULL, " \t");    // get num_acq
			int num_acq = atoi(piece);

			piece = strtok (NULL, " \t");    // get seconds
			int secs = atoi(piece);

			piece = strtok (NULL, " \t");    // get nseconds
			int nsecs = atoi(piece);

			piece = strtok (NULL, " \t");    // get clk1
			int clk1 = atoi(piece);

			piece = strtok (NULL, " \t");    // get clk2
			int clk2 = atoi(piece);

			eeevent neweeevent(num1, num_trig, num_acq, secs, nsecs, clk1, clk2, hv1, hv2, hv3);

			piece = strtok (NULL, " \t");    // get events
			while (piece != NULL) {
				double x = atof(piece);
				piece = strtok (NULL, " \t");    // get more pieces

				if (piece!=NULL) {
					double y = atof(piece);
					piece = strtok (NULL, " \t");    // get more pieces

					int z = atoi(piece);
					piece = strtok (NULL, " \t");    // get more pieces

					neweeevent.gethit(x, y, z);
					//cout << x << " - " << y << " - " << z << endl;
				}
			}

			evector.push_back(neweeevent);
		}
	}
	cout << "Parsing completed: " << evector.size() << " events captured" << endl << endl;

	return evector;
}

const double xmax=40;
const double ymax=84;

void plot_events(int ch, eeevector evector)
{
	char name[256];
	sprintf(name, "canv_ch%d", ch);

	char title[256];
	sprintf(title, "Events ch%d", ch);

	TCanvas *canv = new TCanvas(name,"canvas eff", 800, 600);
	TH2D *hist = new TH2D("", title, 100, -xmax, xmax, 1000, -ymax, ymax);

	for (size_t i=0; i<evector.size(); ++i) {              // for every event
		eeevent event1 = evector[i];
		for (size_t j=0; j<event1.hits[ch].size(); ++j) {   // for every hit in ch
			hit hit1 = event1.hits[ch][j];
			hist->Fill(hit1.x, hit1.y);
		}
	}

	canv->cd();
	hist->Draw("colz");

	cout << "Chamber " << ch << ": " << hist->Integral() << " events" << endl << endl;
}

void cluster_size_study(eeevector evector)
{
	const double step = 0.01;
	const double maxradius = 20;

	TCanvas *canv = new TCanvas("canvas","canvas title", 800, 600);
	canv->cd();
	TH1D *hist = new TH1D("", "Cluster", maxradius/step-1, 0, maxradius);

	for (size_t i=0; i<evector.size(); ++i) {              // for every event
		eeevent event1 = evector[i];
		for (int ch=0; ch<3; ++ch) {                        // for every chamber
			if (event1.hits[ch].size() > 1) {                      // if there are hits in ch
				for (size_t j=0; j<event1.hits[ch].size(); ++j) {   // for every hit in ch
					hit hit1 = event1.hits[ch][j];
					for (size_t k=j+1; k<event1.hits[ch].size(); ++k) {   // for every other hit in ch
						hit hit2 = event1.hits[ch][k];
						double dist = hit2.distance_from(hit1);
						for (double radius=maxradius; radius > dist; radius-=step) {   // for every radius
							hist->Fill(radius);
						}
					}
				}
			}
		}
	}
	hist->SetStats(kFALSE);
	hist->Draw();
	cout << "Done clusters" << endl << endl;
}

void chamber_assign(int chtest, int* ch1, int* ch2)
{
	switch (chtest) {
		case 0: *ch1 = 1; *ch2 = 2; break;
		case 1: *ch1 = 0; *ch2 = 2; break;
		case 2: *ch1 = 0; *ch2 = 1; break;
		default: cout << "Unrecognized chamber" << endl;
	}
}

hit compute_hitpoint(int chtest, hit hit1, hit hit2)
{
	double z, z1, z2;
	switch (chtest) {
		case 0: z = 149.00; z1 =  95.50; z2 =  49.00; break;
		case 1: z =  95.50; z1 = 149.00; z2 =  49.00; break;
		case 2: z =  49.00; z1 = 149.00; z2 =  95.50; break;
		default: cout << "Unrecognized chamber" << endl; exit(1);
	}
	// line equation is: (x-x1)/(x2-x1)=(y-y1)/(y2-y1)=(z-z1)/(z2-z1)=A

	double x1 = hit1.x;
	double x2 = hit2.x;
	double y1 = hit1.y;
	double y2 = hit2.y;

	double A = (z-z1)/(z2-z1);
	double x = (x2-x1)*A +x1;
	double y = (y2-y1)*A +y1;
	return {x, y};
}

void compute_eff(int chtest, eeevector evector)
{
	const double dist_cutoff=3;

	char name_exp[256];
	sprintf(name_exp, "canv_exp_ch%d", chtest);
	char name_det[256];
	sprintf(name_det, "canv_det_ch%d", chtest);
	char name_eff[256];
	sprintf(name_eff, "canv_eff_ch%d", chtest);

	char title_exp[256];
	sprintf(title_exp, "Expected ch%d", chtest);
	char title_det[256];
	sprintf(title_det, "Detected ch%d", chtest);
	char title_eff[256];
	sprintf(title_eff, "Efficiency ch%d", chtest);

	TCanvas *canv_exp = new TCanvas(name_exp,"canvas exp", 800, 600);
	TH2D *hist_exp = new TH2D("", title_exp, 100, -xmax, xmax, 1000, -ymax, ymax);
	TCanvas *canv_det = new TCanvas(name_det,"canvas det", 800, 600);
	TH2D *hist_det = new TH2D("", title_det, 100, -xmax, xmax, 1000, -ymax, ymax);
	TCanvas *canv_eff = new TCanvas(name_eff,"canvas eff", 800, 600);
	TH2D *hist_eff = new TH2D("", title_eff, 100, -xmax, xmax, 1000, -ymax, ymax);

	int expected=0;
	int detected=0;

	int ch1, ch2;
	chamber_assign(chtest, &ch1, &ch2);

	char name_nhits[256];
	sprintf(name_nhits, "canv_nhits_ch%d", chtest);
	char title_nhits[256];
	sprintf(title_eff, "Hits number ch%d", chtest);

	TCanvas *canv_nhits = new TCanvas(name_nhits,"canvas nits", 800, 600);
	TH1D *hist_nhits = new TH1D("", title_nhits, 10, 0, 10);

	for (size_t i=0; i<evector.size(); ++i) {              // for every event
		eeevent event1 = evector[i];
		for (size_t j=0; j<event1.hits[ch1].size(); ++j) {   // for every hit in ch1
			hit hit1 = event1.hits[ch1][j];
			for (size_t k=0; k<event1.hits[ch2].size(); ++k) {   // for every hit in ch2
				hit hit2 = event1.hits[ch2][k];
				hit hit_test = compute_hitpoint(chtest, hit1, hit2);
				if (hit_test.is_inside(xmax, ymax)) {
					int counter=0;
					expected++;
					hist_exp->Fill(hit_test.x, hit_test.y);
					for (size_t h=0; h<event1.hits[chtest].size(); ++h) {   // for every hit in chtest
						hit hitf = event1.hits[chtest][h];
						double dist = hit_test.distance_from(hitf);
						if (dist < dist_cutoff) {
							detected++;
							hist_det->Fill(hitf.x, hitf.y);
							counter++;
						}
					}
					hist_nhits->Fill(counter);
				}
			}
		}
	}

	canv_nhits->cd();
	hist_nhits->Draw();

	canv_exp->cd();
	hist_exp->Draw();

	canv_det->cd();
	hist_det->Draw();

	hist_eff->Divide(hist_det, hist_exp);
	canv_eff->cd();
	hist_eff->Draw("colz");

	cout << "Chamber " << chtest << ":" << endl;
	cout << "Distance cutoff chosen: " << dist_cutoff << endl;
	cout << "Expected events: " << expected << endl;
	cout << "Detected events: " << detected << endl;
	cout << "Efficiency: " << (double)detected/expected << endl << endl;
}

void single_events_fitter(eeevector evector)
{
	eeevector goodevents[3];  // events good for chamber ch
	eeevector perfevents;     // events with a single hit/ch
	for (size_t i=0; i != evector.size(); ++i) {  // for every event
		int counter=0;
		eeevent event1=evector[i];
		if (event1.hits[0].size()==1) counter+=1;
		if (event1.hits[1].size()==1) counter+=2;
		if (event1.hits[2].size()==1) counter+=4;
		if (counter==3 || counter==7) goodevents[2].push_back(event1);
		if (counter==5 || counter==7) goodevents[1].push_back(event1);
		if (counter==6 || counter==7) goodevents[0].push_back(event1);
		if (counter==7) perfevents.push_back(event1);
		if (counter>7) cout << "Unrecognized counter" << endl;
	}
	for (int ch=0; ch<3; ++ch) {
		cout << "Good events for ch" << ch << ": " << goodevents[ch].size() << endl;
	}
	cout << "Perfect events: " << perfevents.size() << endl << endl;

	//~ for (size_t i=0; i<perfevents.size(); ++i) {              // for every event
		//~ eeevent event1 = perfrvents[i];
		//~ hit hit0 = event1.hits[0][0];
		//~ hit hit1 = event1.hits[1][0];
		//~ hit hit2 = event1.hits[2][0];
		//~ hit hit_test = compute_hitpoint(chtest, hit1, hit2);
		//~ if (hit_test.is_inside(xmax, ymax)) {
			//~ int counter=0;
			//~ expected++;
			//~ hist_exp->Fill(hit_test.x, hit_test.y);
			//~ for (size_t h=0; h<event1.hits[chtest].size(); ++h) {   // for every hit in chtest
				//~ hit hitf = event1.hits[chtest][h];
				//~ double dist = hit_test.distance_from(hitf);
				//~ if (dist < dist_cutoff) {
					//~ detected++;
					//~ hist_det->Fill(hitf.x, hitf.y);
					//~ counter++;
				//~ }
			//~ }
			//~ hist_nhits->Fill(counter);
		//~ }
	//~ }
}

void average_hit_number(eeevector evector)
{
	for (int ch=0; ch<3; ++ch) {
		char name[256];
		sprintf(name, "canv_hits_ch%d", ch);

		char title[256];
		sprintf(title, "Hit number ch%d", ch);

		TCanvas *canv = new TCanvas(name,"canvas", 800, 600);
		int nbins=20;
		TH1I *hist = new TH1I("", title, nbins, 0, nbins);

		for (size_t i=0; i != evector.size(); ++i) {  // for every event
			int nhits=evector[i].hits[ch].size();
			hist->Fill(nhits);
		}

		canv->cd();
		hist->Draw();
	}
}

int parser(string path)
{

	eeevector evector;
	evector = parse(path);

	//for (int i = 0; i < 3; i++) plot_events(i, evector);

	//cluster_size_study(evector);
	//evector = clusterize(evector, cluster_size);

	//for (int i = 0; i < 3; i++) compute_eff(i, evector);

	average_hit_number(evector);

	single_events_fitter(evector);

	return 0;
}

int main(int, char** argv)
{
	string path = argv[1];
	parser(path);

	return 0;
}

/* Code graveyard
*
*
*
	hitvector hvector;
	switch (nchamber) {
		case 1: hvector=evector.hits1; break;
		case 2: hvector=evector.hits2; break;
		case 3: hvector=evector.hits3; break;
		default: cout << "Unexpected chamber number" << endl;
	}
*
	if (dist < radius) {
		if (hit1.cluster.size() == 0 && hit1.cluster.size() == 0) counter++;
		hit1.cluster.push_back(hit2);
		hit2.cluster.push_back(hit1);
	}
*
*
*/
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright (c) 2015-2016 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder.  You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright 2009-2014 Sandia Coporation.  Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.

#include <sst/core/sst_config.h>
#include <sst/core/componentInfo.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>

#include <Python.h>  // Before serialization to prevent spurious warnings

#include "gem5.hh"

#include "util.hh"

// System headers
#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

#include <pybind11/embed.h>
#include <pybind11/pybind11.h>

// gem5 Headers
#include <sim/core.hh>
#include <sim/init.hh>
#include <sim/init_signals.hh>
#include <sim/root.hh>
#include <sim/system.hh>
#include <sim/sim_events.hh>
#include <sim/sim_object.hh>
#include <base/logging.hh>
#include <base/debug.hh>

#include <base/pollevent.hh>
#include <base/types.hh>
#include <sim/async.hh>
#include <sim/eventq.hh>
#include <sim/sim_exit.hh>
#include <sim/stat_control.hh>

#include <sst/outgoing_request_bridge.hh>

#include <cassert>

#ifdef fatal  // gem5 sets this
#undef fatal
#endif

// More SST Headers
#include <core/timeConverter.h>

namespace py = pybind11;

gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
    SST::Component(id), threadInitialized(false)
{
    output.init("gem5Component-" + getName() + "->", 1, 0,
                SST::Output::STDOUT);

    std::string cpu_frequency = params.find<std::string>("frequency", "");
    if (cpu_frequency.empty()) {
        output.fatal(
            CALL_INFO, -1, "The frequency of the CPU must be specified.\n"
        );
    }

    // Register a handler to be called on a set frequency.
    timeConverter = registerClock(
        cpu_frequency,
        new SST::Clock::Handler<gem5Component>(this, &gem5Component::clockTick)
    );

    // "cmd" -> gem5's Python
    std::string cmd = params.find<std::string>("cmd", "");
    if (cmd.empty()) {
        output.fatal(
            CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n",
            getName().c_str()
        );
    }

    // Telling SST the command line call to gem5
    args.push_back(const_cast<char*>("sst.x"));
    splitCommandArgs(cmd, args);
    output.output(CALL_INFO, "Command string:  [sst.x %s]\n", cmd.c_str());
    for (size_t i = 0; i < args.size(); ++i) {
        output.output(CALL_INFO, "  Arg [%02zu] = %s\n", i, args[i]);
    }

    // Parsing and setting gem5 debug flags
    std::string gem5_debug_flags = params.find<std::string>("debug_flags", "");
    for (auto const debug_flag: tokenizeString(gem5_debug_flags, {' ', ','})) {
        output.output(CALL_INFO, "Debug flag += %s\n", debug_flag.c_str());
        gem5::setDebugFlag(debug_flag.c_str());
    }

    registerAsPrimaryComponent();
    primaryComponentDoNotEndSim();

    systemPort = \
        loadUserSubComponent<SSTResponderSubComponent>("system_port",0);
    cachePort = \
        loadUserSubComponent<SSTResponderSubComponent>("cache_port", 0);

    systemPort->setTimeConverter(timeConverter);
    systemPort->setOutputStream(&(output));
    cachePort->setTimeConverter(timeConverter);
    cachePort->setOutputStream(&(output));

}

gem5Component::~gem5Component()
{
}

void
gem5Component::init(unsigned phase)
{
    output.output(CALL_INFO," init phase: %u\n", phase);

    if (phase == 0) {
        initPython(args.size(), &args[0]);

        const std::vector<std::string> m5_instantiate_commands = {
            "import m5",
            "m5.instantiate()"
        };
        execPythonCommands(m5_instantiate_commands);

        // calling SimObject.startup()
        const std::vector<std::string> simobject_setup_commands = {
            "import atexit",
            "import _m5.core",
            "import m5",
            "import m5.stats",
            "import m5.objects.Root",
            "root = m5.objects.Root.getInstance()",
            "for obj in root.descendants(): obj.startup()",
            "atexit.register(m5.stats.dump)",
            "atexit.register(_m5.core.doExitCleanup)",
            "m5.stats.reset()"
        };
        execPythonCommands(simobject_setup_commands);

        // find the corresponding SimObject for each SSTResponderSubComponent
        gem5::Root* gem5_root = gem5::Root::root();
        systemPort->findCorrespondingSimObject(gem5_root);
        cachePort->findCorrespondingSimObject(gem5_root);

        // initialize the gem5 event queue
        if (!(threadInitialized)) {
            threadInitialized = true;
            gem5::simulate_limit_event = new gem5::GlobalSimLoopExitEvent(
                gem5::mainEventQueue[0]->getCurTick(),
                "simulate() limit reached",
                0
            );
        }

    }

    systemPort->init(phase);
    cachePort->init(phase);
}

void
gem5Component::setup()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
    systemPort->setup();
    cachePort->setup();
}

void
gem5Component::finish()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being finished.\n");
}

bool
gem5Component::clockTick(SST::Cycle_t currentCycle)
{
    // what to do in a SST's cycle
    gem5::GlobalSimLoopExitEvent *event = simulateGem5(currentCycle);
    clocksProcessed++;
    // gem5 exits due to reasons other than reaching simulation limit
    if (event != gem5::simulate_limit_event) {
        output.output("exiting: curTick()=%lu cause=`%s` code=%d\n",
            gem5::curTick(), event->getCause().c_str(), event->getCode()
        );
        // output gem5 stats
        const std::vector<std::string> output_stats_commands = {
            "import m5.stats"
            "m5.stats.dump()"
        };
        execPythonCommands(output_stats_commands);

        primaryComponentOKToEndSim();
        return true;
    }

    // returning False means the simulation should go on
    return false;

}

#define PyCC(x) (const_cast<char *>(x))

gem5::GlobalSimLoopExitEvent*
gem5Component::simulateGem5(uint64_t current_cycle)
{
    // This function should be similar to simulate() of src/sim/simulate.cc
    // with synchronization barriers removed.

    inform_once("Entering event queue @ %d.  Starting simulation...\n",
                gem5::curTick());

    // Tick conversion
    // The main logic for synchronize SST Tick and gem5 Tick is here.
    // next_end_tick = current_cycle * timeConverter->getFactor()
    uint64_t next_end_tick = \
        timeConverter->convertToCoreTime(current_cycle);

    // Here, if the next event in gem5's queue is not executed within the next
    // cycle, there's no need to enter the gem5's sim loop.
    if (gem5::mainEventQueue[0]->empty() ||
        next_end_tick < gem5::mainEventQueue[0]->getHead()->when()) {
        return gem5::simulate_limit_event;
    }
    gem5::simulate_limit_event->reschedule(next_end_tick);
    gem5::Event *local_event = doSimLoop(gem5::mainEventQueue[0]);
    gem5::BaseGlobalEvent *global_event = local_event->globalEvent();
    gem5::GlobalSimLoopExitEvent *global_exit_event =
        dynamic_cast<gem5::GlobalSimLoopExitEvent *>(global_event);
    return global_exit_event;
}

gem5::Event*
gem5Component::doSimLoop(gem5::EventQueue* eventq)
{
    // This function should be similar to doSimLoop() in src/sim/simulate.cc
    // with synchronization barriers removed.
    gem5::curEventQueue(eventq);
    eventq->handleAsyncInsertions();

    while (true)
    {
        // there should always be at least one event (the SimLoopExitEvent
        // we just scheduled) in the queue

        assert(!eventq->empty());
        assert(gem5::curTick() <= eventq->nextTick() &&
               "event scheduled in the past");

        if (gem5::async_event) {
            // Take the event queue lock in case any of the service
            // routines want to schedule new events.
            if (gem5::async_statdump || gem5::async_statreset) {
                gem5::statistics::schedStatEvent(gem5::async_statdump,
                                                 gem5::async_statreset);
                gem5::async_statdump = false;
                gem5::async_statreset = false;
            }

            if (gem5::async_io) {
                gem5::async_io = false;
                gem5::pollQueue.service();
            }

            if (gem5::async_exit) {
                gem5::async_exit = false;
                gem5::exitSimLoop("user interrupt received");
            }

            if (gem5::async_exception) {
                gem5::async_exception = false;
                return NULL;
            }
        }

        gem5::Event *exit_event = eventq->serviceOne();
        if (exit_event != NULL) {
            return exit_event;
        }
    }
}

int
gem5Component::execPythonCommands(const std::vector<std::string>& commands)
{
    static PyObject *dict =
        py::module_::import("__main__").attr("__dict__").ptr();

    PyObject *result;

    for (auto const command: commands) {
        result = PyRun_String(command.c_str(), Py_file_input, dict, dict);
        if (!result) {
            PyErr_Print();
            return 1;
        }
        Py_DECREF(result);
    }
    return 0;
}

void
gem5Component::initPython(int argc, char *_argv[])
{
    // Initialize gem5 special signal handling.
    gem5::initSignals();

    if (!Py_IsInitialized())
        py::initialize_interpreter(false, argc, _argv);

    auto importer = py::module_::import("importer");
    importer.attr("install")();

    try {
        py::module_::import("m5").attr("main")();
    } catch (py::error_already_set &e) {
        if (!e.matches(PyExc_SystemExit)) {
            std::cerr << e.what();
            output.output(CALL_INFO, "Calling m5.main(...) failed.\n");
        }
    }
}

void
gem5Component::splitCommandArgs(std::string &cmd, std::vector<char*> &args)
{
    std::vector<std::string> parsed_args = tokenizeString(
        cmd, {'\\', ' ', '\'', '\"'}
    );

    for (auto part: parsed_args)
        args.push_back(strdup(part.c_str()));
}
<commit_msg>ext: In sst, set sys.argv up even when not initializing python.<commit_after>// Copyright (c) 2021 The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright (c) 2015-2016 ARM Limited
// All rights reserved.
//
// The license below extends only to copyright in the software and shall
// not be construed as granting a license to any other intellectual
// property including but not limited to intellectual property relating
// to a hardware implementation of the functionality of the software
// licensed hereunder.  You may use the software subject to the license
// terms below provided that you ensure that this notice is replicated
// unmodified and in its entirety in all distributions of the software,
// modified or unmodified, in source code or in binary form.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Copyright 2009-2014 Sandia Coporation.  Under the terms
// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
// Government retains certain rights in this software.
//
// Copyright (c) 2009-2014, Sandia Corporation
// All rights reserved.
//
// For license information, see the LICENSE file in the current directory.

#include <sst/core/sst_config.h>
#include <sst/core/componentInfo.h>
#include <sst/core/interfaces/simpleMem.h>
#include <sst/elements/memHierarchy/memEvent.h>
#include <sst/elements/memHierarchy/memTypes.h>
#include <sst/elements/memHierarchy/util.h>

#include <Python.h>  // Before serialization to prevent spurious warnings

#include "gem5.hh"

#include "util.hh"

// System headers
#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

#include <pybind11/embed.h>
#include <pybind11/pybind11.h>

// gem5 Headers
#include <sim/core.hh>
#include <sim/init.hh>
#include <sim/init_signals.hh>
#include <sim/root.hh>
#include <sim/system.hh>
#include <sim/sim_events.hh>
#include <sim/sim_object.hh>
#include <base/logging.hh>
#include <base/debug.hh>

#include <base/pollevent.hh>
#include <base/types.hh>
#include <sim/async.hh>
#include <sim/eventq.hh>
#include <sim/sim_exit.hh>
#include <sim/stat_control.hh>

#include <sst/outgoing_request_bridge.hh>

#include <cassert>

#ifdef fatal  // gem5 sets this
#undef fatal
#endif

// More SST Headers
#include <core/timeConverter.h>

namespace py = pybind11;

gem5Component::gem5Component(SST::ComponentId_t id, SST::Params& params):
    SST::Component(id), threadInitialized(false)
{
    output.init("gem5Component-" + getName() + "->", 1, 0,
                SST::Output::STDOUT);

    std::string cpu_frequency = params.find<std::string>("frequency", "");
    if (cpu_frequency.empty()) {
        output.fatal(
            CALL_INFO, -1, "The frequency of the CPU must be specified.\n"
        );
    }

    // Register a handler to be called on a set frequency.
    timeConverter = registerClock(
        cpu_frequency,
        new SST::Clock::Handler<gem5Component>(this, &gem5Component::clockTick)
    );

    // "cmd" -> gem5's Python
    std::string cmd = params.find<std::string>("cmd", "");
    if (cmd.empty()) {
        output.fatal(
            CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n",
            getName().c_str()
        );
    }

    // Telling SST the command line call to gem5
    args.push_back(const_cast<char*>("sst.x"));
    splitCommandArgs(cmd, args);
    output.output(CALL_INFO, "Command string:  [sst.x %s]\n", cmd.c_str());
    for (size_t i = 0; i < args.size(); ++i) {
        output.output(CALL_INFO, "  Arg [%02zu] = %s\n", i, args[i]);
    }

    // Parsing and setting gem5 debug flags
    std::string gem5_debug_flags = params.find<std::string>("debug_flags", "");
    for (auto const debug_flag: tokenizeString(gem5_debug_flags, {' ', ','})) {
        output.output(CALL_INFO, "Debug flag += %s\n", debug_flag.c_str());
        gem5::setDebugFlag(debug_flag.c_str());
    }

    registerAsPrimaryComponent();
    primaryComponentDoNotEndSim();

    systemPort = \
        loadUserSubComponent<SSTResponderSubComponent>("system_port",0);
    cachePort = \
        loadUserSubComponent<SSTResponderSubComponent>("cache_port", 0);

    systemPort->setTimeConverter(timeConverter);
    systemPort->setOutputStream(&(output));
    cachePort->setTimeConverter(timeConverter);
    cachePort->setOutputStream(&(output));

}

gem5Component::~gem5Component()
{
}

void
gem5Component::init(unsigned phase)
{
    output.output(CALL_INFO," init phase: %u\n", phase);

    if (phase == 0) {
        initPython(args.size(), &args[0]);

        const std::vector<std::string> m5_instantiate_commands = {
            "import m5",
            "m5.instantiate()"
        };
        execPythonCommands(m5_instantiate_commands);

        // calling SimObject.startup()
        const std::vector<std::string> simobject_setup_commands = {
            "import atexit",
            "import _m5.core",
            "import m5",
            "import m5.stats",
            "import m5.objects.Root",
            "root = m5.objects.Root.getInstance()",
            "for obj in root.descendants(): obj.startup()",
            "atexit.register(m5.stats.dump)",
            "atexit.register(_m5.core.doExitCleanup)",
            "m5.stats.reset()"
        };
        execPythonCommands(simobject_setup_commands);

        // find the corresponding SimObject for each SSTResponderSubComponent
        gem5::Root* gem5_root = gem5::Root::root();
        systemPort->findCorrespondingSimObject(gem5_root);
        cachePort->findCorrespondingSimObject(gem5_root);

        // initialize the gem5 event queue
        if (!(threadInitialized)) {
            threadInitialized = true;
            gem5::simulate_limit_event = new gem5::GlobalSimLoopExitEvent(
                gem5::mainEventQueue[0]->getCurTick(),
                "simulate() limit reached",
                0
            );
        }

    }

    systemPort->init(phase);
    cachePort->init(phase);
}

void
gem5Component::setup()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being setup.\n");
    systemPort->setup();
    cachePort->setup();
}

void
gem5Component::finish()
{
    output.verbose(CALL_INFO, 1, 0, "Component is being finished.\n");
}

bool
gem5Component::clockTick(SST::Cycle_t currentCycle)
{
    // what to do in a SST's cycle
    gem5::GlobalSimLoopExitEvent *event = simulateGem5(currentCycle);
    clocksProcessed++;
    // gem5 exits due to reasons other than reaching simulation limit
    if (event != gem5::simulate_limit_event) {
        output.output("exiting: curTick()=%lu cause=`%s` code=%d\n",
            gem5::curTick(), event->getCause().c_str(), event->getCode()
        );
        // output gem5 stats
        const std::vector<std::string> output_stats_commands = {
            "import m5.stats"
            "m5.stats.dump()"
        };
        execPythonCommands(output_stats_commands);

        primaryComponentOKToEndSim();
        return true;
    }

    // returning False means the simulation should go on
    return false;

}

#define PyCC(x) (const_cast<char *>(x))

gem5::GlobalSimLoopExitEvent*
gem5Component::simulateGem5(uint64_t current_cycle)
{
    // This function should be similar to simulate() of src/sim/simulate.cc
    // with synchronization barriers removed.

    inform_once("Entering event queue @ %d.  Starting simulation...\n",
                gem5::curTick());

    // Tick conversion
    // The main logic for synchronize SST Tick and gem5 Tick is here.
    // next_end_tick = current_cycle * timeConverter->getFactor()
    uint64_t next_end_tick = \
        timeConverter->convertToCoreTime(current_cycle);

    // Here, if the next event in gem5's queue is not executed within the next
    // cycle, there's no need to enter the gem5's sim loop.
    if (gem5::mainEventQueue[0]->empty() ||
        next_end_tick < gem5::mainEventQueue[0]->getHead()->when()) {
        return gem5::simulate_limit_event;
    }
    gem5::simulate_limit_event->reschedule(next_end_tick);
    gem5::Event *local_event = doSimLoop(gem5::mainEventQueue[0]);
    gem5::BaseGlobalEvent *global_event = local_event->globalEvent();
    gem5::GlobalSimLoopExitEvent *global_exit_event =
        dynamic_cast<gem5::GlobalSimLoopExitEvent *>(global_event);
    return global_exit_event;
}

gem5::Event*
gem5Component::doSimLoop(gem5::EventQueue* eventq)
{
    // This function should be similar to doSimLoop() in src/sim/simulate.cc
    // with synchronization barriers removed.
    gem5::curEventQueue(eventq);
    eventq->handleAsyncInsertions();

    while (true)
    {
        // there should always be at least one event (the SimLoopExitEvent
        // we just scheduled) in the queue

        assert(!eventq->empty());
        assert(gem5::curTick() <= eventq->nextTick() &&
               "event scheduled in the past");

        if (gem5::async_event) {
            // Take the event queue lock in case any of the service
            // routines want to schedule new events.
            if (gem5::async_statdump || gem5::async_statreset) {
                gem5::statistics::schedStatEvent(gem5::async_statdump,
                                                 gem5::async_statreset);
                gem5::async_statdump = false;
                gem5::async_statreset = false;
            }

            if (gem5::async_io) {
                gem5::async_io = false;
                gem5::pollQueue.service();
            }

            if (gem5::async_exit) {
                gem5::async_exit = false;
                gem5::exitSimLoop("user interrupt received");
            }

            if (gem5::async_exception) {
                gem5::async_exception = false;
                return NULL;
            }
        }

        gem5::Event *exit_event = eventq->serviceOne();
        if (exit_event != NULL) {
            return exit_event;
        }
    }
}

int
gem5Component::execPythonCommands(const std::vector<std::string>& commands)
{
    static PyObject *dict =
        py::module_::import("__main__").attr("__dict__").ptr();

    PyObject *result;

    for (auto const command: commands) {
        result = PyRun_String(command.c_str(), Py_file_input, dict, dict);
        if (!result) {
            PyErr_Print();
            return 1;
        }
        Py_DECREF(result);
    }
    return 0;
}

void
gem5Component::initPython(int argc, char *_argv[])
{
    // Initialize gem5 special signal handling.
    gem5::initSignals();

    if (!Py_IsInitialized()) {
        py::initialize_interpreter(true, argc, _argv);
    } else {
        // pybind doesn't provide a way to set sys.argv if not initializing the
        // interpreter, so we have to do that manually if it's already running.
        py::list py_argv;
        auto sys = py::module::import("sys");
        if (py::hasattr(sys, "argv")) {
            // sys.argv already exists, so grab that.
            py_argv = sys.attr("argv");
        } else {
            // sys.argv doesn't exist, so create it.
            sys.add_object("argv", py_argv);
        }
        // Clear out argv just in case it has something in it.
        py_argv.attr("clear")();

        // Fill it with our argvs.
        for (int i = 0; i < argc; i++)
            py_argv.append(_argv[i]);
    }

    auto importer = py::module_::import("importer");
    importer.attr("install")();

    try {
        py::module_::import("m5").attr("main")();
    } catch (py::error_already_set &e) {
        if (!e.matches(PyExc_SystemExit)) {
            std::cerr << e.what();
            output.output(CALL_INFO, "Calling m5.main(...) failed.\n");
        }
    }
}

void
gem5Component::splitCommandArgs(std::string &cmd, std::vector<char*> &args)
{
    std::vector<std::string> parsed_args = tokenizeString(
        cmd, {'\\', ' ', '\'', '\"'}
    );

    for (auto part: parsed_args)
        args.push_back(strdup(part.c_str()));
}
<|endoftext|>


<commit_before>#pragma once

#include "managed_texture.hpp"
#include "data_formats.hpp"

#include "../platform/platform.hpp"

#include "../coding/lodepng_io.hpp"

namespace gil = boost::gil;
namespace mpl = boost::mpl;

namespace yg
{
  namespace gl
  {

    template <typename Traits, bool IsBacked>
    class Texture{};

    inline m2::PointU const GetDimensions(string const & fileName)
    {
      ReaderPtr<Reader> reader = GetPlatform().GetReader(fileName);
      gil::point2<ptrdiff_t> size = gil::lodepng_read_dimensions(reader);
      return m2::PointU(size.x, size.y);
    }

    template <typename Traits>
    class Texture<Traits, false> : public BaseTexture
    {
    public:

      typedef Traits traits_t;
      typedef typename Traits::pixel_t pixel_t;
      typedef typename Traits::const_pixel_t const_pixel_t;
      typedef typename Traits::view_t view_t;
      typedef typename Traits::const_view_t const_view_t;
      typedef typename Traits::image_t image_t;

      static const int maxChannelVal = Traits::maxChannelVal;
      static const int channelScaleFactor = Traits::channelScaleFactor;
      static const int gl_pixel_data_type = Traits::gl_pixel_data_type;
      static const int gl_pixel_format_type = Traits::gl_pixel_format_type;

    private:

      void upload(void * data)
      {
        makeCurrent();

        OGLCHECK(glTexImage2D(
          GL_TEXTURE_2D,
          0,
          Traits::gl_pixel_format_type,
          width(),
          height(),
          0,
          Traits::gl_pixel_format_type,
          Traits::gl_pixel_data_type,
          data));
      }

    public:

      Texture(string const & fileName) : BaseTexture(GetDimensions(fileName))
      {
        typename Traits::image_t image(width(), height());
        ReaderPtr<Reader> reader = GetPlatform().GetReader(fileName);
        gil::lodepng_read_and_convert_image(reader, image, typename Traits::color_converter());
        upload(&gil::view(image)(0, 0));
      }

      Texture(unsigned width, unsigned height)
        : BaseTexture(width, height)
      {
        upload(0);
      }

      void fill(yg::Color const & c)
      {
        makeCurrent();

        typename Traits::image_t image(width(), height());

        typename Traits::pixel_t val = Traits::createPixel(c);

        typename Traits::view_t v = gil::view(image);

        for (size_t y = 0; y < height(); ++y)
          for (size_t x = 0; x < width(); ++x)
            v(x, y) = val;

        upload(&v(0, 0));
      }

      void dump(char const * fileName)
      {
        makeCurrent();
        std::string const fullPath = GetPlatform().WritablePathForFile(fileName);

        typename Traits::image_t image(width(), height());

#ifndef OMIM_GL_ES
      OGLCHECK(glGetTexImage(
          GL_TEXTURE_2D,
          0,
          Traits::gl_pixel_format_type,
          Traits::gl_pixel_data_type,
          &gil::view(image)(0, 0)));
//      boost::gil::lodepng_write_view(fullPath.c_str(), gil::view(image));
#endif

      }
    };

    template <typename Traits>
    class Texture<Traits, true> : public ManagedTexture
    {
    public:

      typedef Traits traits_t;
      typedef typename Traits::pixel_t pixel_t;
      typedef typename Traits::const_pixel_t const_pixel_t;
      typedef typename Traits::view_t view_t;
      typedef typename Traits::const_view_t const_view_t;
      typedef typename Traits::image_t image_t;

      static const int maxChannelVal = Traits::maxChannelVal;
      static const int channelScaleFactor = Traits::channelScaleFactor;
      static const int gl_pixel_data_type = Traits::gl_pixel_data_type;
      static const int gl_pixel_format_type = Traits::gl_pixel_format_type;

    private:

      void updateDirty(m2::RectU const & r);

    public:

      void upload(void * data);
      void upload(void * data, m2::RectU const & r);

      /// Create the texture loading it from file
      Texture(string const & fileName);
      /// Create the texture with the predefined dimensions
      Texture(size_t width, size_t height);
      Texture(m2::RectU const & r);

      /// You can call this anytime, regardless the locking status of the texture.
      /// const_view_t const_view() const;
      /// You can call this on locked texture only. All your changess to this view's data will be
      /// uploaded to the video memory on unlock()
      view_t view(size_t width, size_t height);

      void fill(yg::Color const & c);

      /// dump the texture into the file.
      void dump(char const * fileName);
      /// videomem -> sysmem texture image transfer.
      /// @warning could be very slow. use with caution.
      void readback();

      void randomize();
    };

    typedef Texture<RGBA8Traits, true> RGBA8Texture;
    typedef Texture<RGBA4Traits, true> RGBA4Texture;

    typedef Texture<RGBA8Traits, false> RawRGBA8Texture;
    typedef Texture<RGBA4Traits, false> RawRGBA4Texture;

    typedef Texture<RGB565Traits, false> RawRGB565Texture;

    template <typename Traits>
    Texture<Traits, true>::Texture(const m2::RectU &r)
      : ManagedTexture(r.SizeX(), r.SizeY(), sizeof(pixel_t))
    {
      upload(0);
    }

    template <typename Traits>
    Texture<Traits, true>::Texture(size_t width, size_t height)
      : ManagedTexture(width, height, sizeof(pixel_t))
    {
      upload(0);
    }

    template <typename Traits>
    Texture<Traits, true>::Texture(string const & fileName) : ManagedTexture(GetDimensions(fileName), sizeof(pixel_t))
    {
      lock();
      view_t v = view(width(), height());
      ReaderPtr<Reader> reader = GetPlatform().GetReader(fileName);
      gil::lodepng_read_and_convert_view(reader, v, typename Traits::color_converter());
      upload(&v(0, 0));
      unlock();
    }

    template <typename Traits>
    typename Texture<Traits, true>::view_t Texture<Traits, true>::view(size_t w, size_t h)
    {
      ASSERT(m_isLocked, ("non const access to unlocked texture!"));
      return gil::interleaved_view(
          w,
          h,
          (pixel_t*)auxData(),
          w * sizeof(pixel_t));
    }

/*    template <typename Traits>
    typename Texture<Traits, true>::const_view_t Texture<Traits, true>::const_view() const
    {
      return gil::const_view(m_image);
    }
 */

    template <typename Traits>
    void Texture<Traits, true>::upload(void * data)
    {
      makeCurrent();

      OGLCHECK(glTexImage2D(
         GL_TEXTURE_2D,
         0,
         gl_pixel_format_type,
         width(),
         height(),
         0,
         gl_pixel_format_type,
         gl_pixel_data_type,
         data));
    }

    template <typename Traits>
    void Texture<Traits, true>::upload(void * data, m2::RectU const & r)
    {
      makeCurrent();
      /// Uploading texture data
      OGLCHECK(glTexSubImage2D(
         GL_TEXTURE_2D,
         0,
         r.minX(),
         r.minY(),
         r.SizeX(),
         r.SizeY(),
         gl_pixel_format_type,
         gl_pixel_data_type,
         data));
    }

    template <typename Traits>
    void Texture<Traits, true>::randomize()
    {
      makeCurrent();
      lock();
      view_t v = view(width(), height());

      for (size_t y = 0; y < height(); ++y)
        for (size_t x = 0; x < width(); ++x)
          v(x, y) = pixel_t(rand() % maxChannelVal, rand() % maxChannelVal, rand() % maxChannelVal, maxChannelVal);

      upload(&v(0, 0), m2::RectU(0, 0, width(), height()));
      unlock();
    }

    template <typename Traits>
    void Texture<Traits, true>::readback()
    {
      makeCurrent();
#ifndef OMIM_GL_ES
      OGLCHECK(glGetTexImage(
          GL_TEXTURE_2D,
          0,
          gl_pixel_format_type,
          Traits::gl_pixel_data_type,
          &view(width(), height())(0, 0)));
#else
          ASSERT(false, ("no glGetTexImage function in OpenGL ES"));
#endif
    }

    template <typename Traits>
    void Texture<Traits, true>::dump(char const * fileName)
    {
      lock();
      readback();
      std::string const fullPath = GetPlatform().WritablePathForFile(fileName);
#ifndef OMIM_GL_ES
//      boost::gil::lodepng_write_view(fullPath.c_str(), view(width(), height()));
#endif
      unlock();
    }

    template <typename Traits>
    void Texture<Traits, true>::fill(yg::Color const & /*c*/)
    {
/*      makeCurrent();
      lock();
      view_t v = view();

      pixel_t val((c.r / 255.0f) * maxChannelVal,
                  (c.g / 255.0f) * maxChannelVal,
                  (c.b / 255.0f) * maxChannelVal,
                  (c.a / 255.0f) * maxChannelVal);

      for (size_t y = 0; y < height(); ++y)
        for (size_t x = 0; x < width(); ++x)
          v(x, y) = val;

      addDirtyRect(m2::RectU(0, 0, width(), height()));
      unlock();
 */
    }
  }
}
<commit_msg>Warning fix<commit_after>#pragma once

#include "managed_texture.hpp"
#include "data_formats.hpp"

#include "../platform/platform.hpp"

#include "../coding/lodepng_io.hpp"

namespace gil = boost::gil;
namespace mpl = boost::mpl;

namespace yg
{
  namespace gl
  {

    template <typename Traits, bool IsBacked>
    class Texture{};

    inline m2::PointU const GetDimensions(string const & fileName)
    {
      ReaderPtr<Reader> reader = GetPlatform().GetReader(fileName);
      gil::point2<ptrdiff_t> size = gil::lodepng_read_dimensions(reader);
      return m2::PointU(size.x, size.y);
    }

    template <typename Traits>
    class Texture<Traits, false> : public BaseTexture
    {
    public:

      typedef Traits traits_t;
      typedef typename Traits::pixel_t pixel_t;
      typedef typename Traits::const_pixel_t const_pixel_t;
      typedef typename Traits::view_t view_t;
      typedef typename Traits::const_view_t const_view_t;
      typedef typename Traits::image_t image_t;

      static const int maxChannelVal = Traits::maxChannelVal;
      static const int channelScaleFactor = Traits::channelScaleFactor;
      static const int gl_pixel_data_type = Traits::gl_pixel_data_type;
      static const int gl_pixel_format_type = Traits::gl_pixel_format_type;

    private:

      void upload(void * data)
      {
        makeCurrent();

        OGLCHECK(glTexImage2D(
          GL_TEXTURE_2D,
          0,
          Traits::gl_pixel_format_type,
          width(),
          height(),
          0,
          Traits::gl_pixel_format_type,
          Traits::gl_pixel_data_type,
          data));
      }

    public:

      Texture(string const & fileName) : BaseTexture(GetDimensions(fileName))
      {
        typename Traits::image_t image(width(), height());
        ReaderPtr<Reader> reader = GetPlatform().GetReader(fileName);
        gil::lodepng_read_and_convert_image(reader, image, typename Traits::color_converter());
        upload(&gil::view(image)(0, 0));
      }

      Texture(unsigned width, unsigned height)
        : BaseTexture(width, height)
      {
        upload(0);
      }

      void fill(yg::Color const & c)
      {
        makeCurrent();

        typename Traits::image_t image(width(), height());

        typename Traits::pixel_t val = Traits::createPixel(c);

        typename Traits::view_t v = gil::view(image);

        for (size_t y = 0; y < height(); ++y)
          for (size_t x = 0; x < width(); ++x)
            v(x, y) = val;

        upload(&v(0, 0));
      }

      void dump(char const * fileName)
      {
        makeCurrent();
//        std::string const fullPath = GetPlatform().WritablePathForFile(fileName);

        typename Traits::image_t image(width(), height());

#ifndef OMIM_GL_ES
      OGLCHECK(glGetTexImage(
          GL_TEXTURE_2D,
          0,
          Traits::gl_pixel_format_type,
          Traits::gl_pixel_data_type,
          &gil::view(image)(0, 0)));
//      boost::gil::lodepng_write_view(fullPath.c_str(), gil::view(image));
#endif

      }
    };

    template <typename Traits>
    class Texture<Traits, true> : public ManagedTexture
    {
    public:

      typedef Traits traits_t;
      typedef typename Traits::pixel_t pixel_t;
      typedef typename Traits::const_pixel_t const_pixel_t;
      typedef typename Traits::view_t view_t;
      typedef typename Traits::const_view_t const_view_t;
      typedef typename Traits::image_t image_t;

      static const int maxChannelVal = Traits::maxChannelVal;
      static const int channelScaleFactor = Traits::channelScaleFactor;
      static const int gl_pixel_data_type = Traits::gl_pixel_data_type;
      static const int gl_pixel_format_type = Traits::gl_pixel_format_type;

    private:

      void updateDirty(m2::RectU const & r);

    public:

      void upload(void * data);
      void upload(void * data, m2::RectU const & r);

      /// Create the texture loading it from file
      Texture(string const & fileName);
      /// Create the texture with the predefined dimensions
      Texture(size_t width, size_t height);
      Texture(m2::RectU const & r);

      /// You can call this anytime, regardless the locking status of the texture.
      /// const_view_t const_view() const;
      /// You can call this on locked texture only. All your changess to this view's data will be
      /// uploaded to the video memory on unlock()
      view_t view(size_t width, size_t height);

      void fill(yg::Color const & c);

      /// dump the texture into the file.
      void dump(char const * fileName);
      /// videomem -> sysmem texture image transfer.
      /// @warning could be very slow. use with caution.
      void readback();

      void randomize();
    };

    typedef Texture<RGBA8Traits, true> RGBA8Texture;
    typedef Texture<RGBA4Traits, true> RGBA4Texture;

    typedef Texture<RGBA8Traits, false> RawRGBA8Texture;
    typedef Texture<RGBA4Traits, false> RawRGBA4Texture;

    typedef Texture<RGB565Traits, false> RawRGB565Texture;

    template <typename Traits>
    Texture<Traits, true>::Texture(const m2::RectU &r)
      : ManagedTexture(r.SizeX(), r.SizeY(), sizeof(pixel_t))
    {
      upload(0);
    }

    template <typename Traits>
    Texture<Traits, true>::Texture(size_t width, size_t height)
      : ManagedTexture(width, height, sizeof(pixel_t))
    {
      upload(0);
    }

    template <typename Traits>
    Texture<Traits, true>::Texture(string const & fileName) : ManagedTexture(GetDimensions(fileName), sizeof(pixel_t))
    {
      lock();
      view_t v = view(width(), height());
      ReaderPtr<Reader> reader = GetPlatform().GetReader(fileName);
      gil::lodepng_read_and_convert_view(reader, v, typename Traits::color_converter());
      upload(&v(0, 0));
      unlock();
    }

    template <typename Traits>
    typename Texture<Traits, true>::view_t Texture<Traits, true>::view(size_t w, size_t h)
    {
      ASSERT(m_isLocked, ("non const access to unlocked texture!"));
      return gil::interleaved_view(
          w,
          h,
          (pixel_t*)auxData(),
          w * sizeof(pixel_t));
    }

/*    template <typename Traits>
    typename Texture<Traits, true>::const_view_t Texture<Traits, true>::const_view() const
    {
      return gil::const_view(m_image);
    }
 */

    template <typename Traits>
    void Texture<Traits, true>::upload(void * data)
    {
      makeCurrent();

      OGLCHECK(glTexImage2D(
         GL_TEXTURE_2D,
         0,
         gl_pixel_format_type,
         width(),
         height(),
         0,
         gl_pixel_format_type,
         gl_pixel_data_type,
         data));
    }

    template <typename Traits>
    void Texture<Traits, true>::upload(void * data, m2::RectU const & r)
    {
      makeCurrent();
      /// Uploading texture data
      OGLCHECK(glTexSubImage2D(
         GL_TEXTURE_2D,
         0,
         r.minX(),
         r.minY(),
         r.SizeX(),
         r.SizeY(),
         gl_pixel_format_type,
         gl_pixel_data_type,
         data));
    }

    template <typename Traits>
    void Texture<Traits, true>::randomize()
    {
      makeCurrent();
      lock();
      view_t v = view(width(), height());

      for (size_t y = 0; y < height(); ++y)
        for (size_t x = 0; x < width(); ++x)
          v(x, y) = pixel_t(rand() % maxChannelVal, rand() % maxChannelVal, rand() % maxChannelVal, maxChannelVal);

      upload(&v(0, 0), m2::RectU(0, 0, width(), height()));
      unlock();
    }

    template <typename Traits>
    void Texture<Traits, true>::readback()
    {
      makeCurrent();
#ifndef OMIM_GL_ES
      OGLCHECK(glGetTexImage(
          GL_TEXTURE_2D,
          0,
          gl_pixel_format_type,
          Traits::gl_pixel_data_type,
          &view(width(), height())(0, 0)));
#else
          ASSERT(false, ("no glGetTexImage function in OpenGL ES"));
#endif
    }

    template <typename Traits>
    void Texture<Traits, true>::dump(char const * fileName)
    {
      lock();
      readback();
//      std::string const fullPath = GetPlatform().WritablePathForFile(fileName);
#ifndef OMIM_GL_ES
//      boost::gil::lodepng_write_view(fullPath.c_str(), view(width(), height()));
#endif
      unlock();
    }

    template <typename Traits>
    void Texture<Traits, true>::fill(yg::Color const & /*c*/)
    {
/*      makeCurrent();
      lock();
      view_t v = view();

      pixel_t val((c.r / 255.0f) * maxChannelVal,
                  (c.g / 255.0f) * maxChannelVal,
                  (c.b / 255.0f) * maxChannelVal,
                  (c.a / 255.0f) * maxChannelVal);

      for (size_t y = 0; y < height(); ++y)
        for (size_t x = 0; x < width(); ++x)
          v(x, y) = val;

      addDirtyRect(m2::RectU(0, 0, width(), height()));
      unlock();
 */
    }
  }
}
<|endoftext|>


<commit_before>/*
CS 3304
Chris Chan
Last updated 9/25/14
Use a linked queue to convert a base-10 fraction to an equivalent fraction in base-2 to base-9 based on user input.
Prompt user for a decimal fraction between 0 and 1.
Prompt user for a number base to convert the fraction to. (radix)
Multiply the given fraction by radix, ignoring the value in the units place, until the product reaches zero, or until the desired number of binary places have been reached
The ignored values will be enqueued and then dequeued to represent the converted fraction.
*/

#include <iostream>
using namespace std;

class Queue{
	private:
		class QueueNode{
			private:
				int myInt;
				QueueNode * next;
			public:
				QueueNode(int i=0, QueueNode * n = NULL) {myInt=i; next=n;}
				~QueueNode(){}
				int getMyInt() {return myInt;}
				void setMyInt(int i) {myInt=i;}
				QueueNode * getNext() {return next;}
				void setNext(QueueNode * n) {next=n;}
		};
		QueueNode * front;
		QueueNode * back;
	public:
		Queue(QueueNode * h=NULL){front=h; back=h;}
		~Queue();
		bool isEmpty();
		void Enqueue(int);
		int Dequeue();
};

int getInt();
float getDecimal();
void convertBase(float, int);

int main(){
	enum menuChoices {CONVERTBASE, EXIT};
	int choice=0;
	cout << "Lab Exercise for Chapter 8 for Linked Queues" << endl;
	while(choice!=2){
		cout << "Please pick from the following options:" << endl;
		cout << "[1] Convert a decimal fraction to another base." << endl;
		cout << "[2] Exit" << endl << endl;
		choice = getInt();
		cout << endl;
		switch(choice-1){
			case CONVERTBASE:
				float newNum;
				int newBase;
				cout << "Enter a decimal." << endl << endl;
				newNum = getDecimal();
				cout << endl;
				cout << "Enter a base to convert to (from 2 to 9)." << endl << endl;
				newBase = getInt();
				if(newBase<=1 || newBase>=10){
					cout << "Please enter a number between 2 to 9." << endl << endl;
					newBase = getInt();
				}
				cout << endl;
				convertBase(newNum, newBase);
				break;
			case EXIT:
				cout << "Goodbye." << endl << endl;
				break;
			default:
				cout << "Please enter a valid option." << endl << endl;
		}
	}
  return 0;
}

float getDecimal(){
	float input;
	do{
		if(cin.fail()){ //if stream buffer had previously failed, clear and reset for valid input
			cin.clear();
			cin.ignore(INT_MAX, '\n');
		}

		cin >> input;

		if(cin.fail()){
			cout << "Not a decimal." << endl << endl;
		}
		if(input<=0 || input>=1){
			cout << "Please enter a fraction between 0 and 1" << endl << endl;
		}
	}while(cin.fail() || input<=0 || input>=1);
	return input;
}

int getInt(){
	int input;
	do{
		if(cin.fail()){ //if stream buffer had previously failed, clear and reset for valid input
			cin.clear();
			cin.ignore(INT_MAX, '\n');
		}

		cin >> input;

		if(cin.fail()){
			cout << "Not an integer." << endl << endl;
		}
	}while(cin.fail());
	return input;
}

void convertBase(float decimal, int newBase){
	float product=decimal;
	Queue * convDecimal = new Queue();
	while(product!=0){
		product*=newBase;
		convDecimal->Enqueue(floor(product));
		product-=floor(product);
	}
	cout << decimal << " converted to base" << newBase << " is 0.";
	while(!convDecimal->isEmpty()){
		cout << convDecimal->Dequeue();
	}
	cout << endl << endl;
}

bool Queue::isEmpty(){
	return front==NULL;
}

void Queue::Enqueue(int newInt){
	if(front==NULL){
		QueueNode * t = new QueueNode(newInt);
		front=t;
		back=t;
	}
	else{
		QueueNode * t = new QueueNode(newInt);
		back->setNext(t);
		back=t;
	}
}

int Queue::Dequeue(){
	QueueNode * tmp = front;
	front = tmp->getNext();
	int frontInt = tmp->getMyInt();
	delete tmp;
	return frontInt;
}
<commit_msg>Update LabCh8.cpp<commit_after>/*
CS 3304
Chris Chan
Last updated 9/29/14
Use a linked queue to convert a base-10 fraction to an equivalent fraction in base-2 to base-9 based on user input.
Prompt user for a decimal fraction between 0 and 1.
Prompt user for a number base to convert the fraction to. (radix)
Multiply the given fraction by radix, ignoring the value in the units place, until the product reaches zero, or until the desired number of binary places have been reached
The ignored values will be enqueued and then dequeued to represent the converted fraction.
*/

#include <iostream>
#include <string>
using namespace std;

class Queue{
	private:
		class QueueNode{
			private:
				int myInt;
				QueueNode * next;
			public:
				QueueNode(int i=0, QueueNode * n = NULL) {myInt=i; next=n;}
				~QueueNode(){}
				int getMyInt() {return myInt;}
				void setMyInt(int i) {myInt=i;}
				QueueNode * getNext() {return next;}
				void setNext(QueueNode * n) {next=n;}
		};
		QueueNode * front;
		QueueNode * back;
	public:
		Queue(QueueNode * h=NULL){front=h; back=h;}
		~Queue();
		bool isEmpty();
		void Enqueue(int);
		int Dequeue();
};

int getInt();
string getDecimal();
void convertBase(string, int);

int main(){
	string newNum;
	int newBase;
	enum menuChoices {CONVERTBASE, EXIT};
	int choice=0;
	cout << "Lab Exercise for Chapter 8 for Linked Queues" << endl;
	while(choice!=2){
		cout << "Please pick from the following options:" << endl;
		cout << "[1] Convert a decimal fraction to another base." << endl;
		cout << "[2] Exit" << endl << endl;
		choice = getInt();
		cout << endl;
		switch(choice-1){
			case CONVERTBASE:
				cout << "Enter a decimal." << endl << endl;
				newNum = getDecimal();
				cout << endl;
				cout << "Enter a base to convert to (from 2 to 9)." << endl << endl;
				newBase = getInt();
				if(newBase<=1 || newBase>=10){
					cout << "Please enter a number between 2 to 9." << endl << endl;
					newBase = getInt();
				}
				cout << endl;
				convertBase(newNum, newBase);
				break;
			case EXIT:
				cout << "Goodbye." << endl << endl;
				break;
			default:
				cout << "Please enter a valid option." << endl << endl;
		}
	}
  return 0;
}

string getDecimal(){
	string input;
	double decimal=0;
	do{
		if(cin.fail()){ //if stream buffer had previously failed, clear and reset for valid input
			cin.clear();
			cin.ignore(INT_MAX, '\n');
		}

		cin >> input;
		decimal = atof(input.c_str());
		if(cin.fail()){
			cout << "Not a decimal." << endl << endl;
		}
		if(decimal<=0 || decimal>=1){
			cout << "Please enter a fraction between 0 and 1" << endl << endl;
		}
	}while(cin.fail() || decimal<=0 || decimal>=1);

	//cout << input.substr(input.find(".")+1).size() << " this is a test." << endl;
	return input;
}

int getInt(){
	int input;
	do{
		if(cin.fail()){ //if stream buffer had previously failed, clear and reset for valid input
			cin.clear();
			cin.ignore(INT_MAX, '\n');
		}

		cin >> input;

		if(cin.fail()){
			cout << "Not an integer." << endl << endl;
		}
	}while(cin.fail());
	return input;
}

void convertBase(string decimal, int newBase){
	double product=atof(decimal.c_str());
	int count=0;
	Queue * convDecimal = new Queue();
	while(product!=0 && count<decimal.substr(decimal.find(".")+1).size()){
		product*=newBase;
		convDecimal->Enqueue(floor(product));
		product-=floor(product);
		count++;
	}
	cout << decimal << " converted to base " << newBase << " is 0.";
	while(!convDecimal->isEmpty()){
		cout << convDecimal->Dequeue();
	}
	cout << endl << endl;
}

bool Queue::isEmpty(){
	return front==NULL;
}

void Queue::Enqueue(int newInt){
	if(front==NULL){
		QueueNode * t = new QueueNode(newInt);
		front=t;
		back=t;
	}
	else{
		QueueNode * t = new QueueNode(newInt);
		back->setNext(t);
		back=t;
	}
}

int Queue::Dequeue(){
	QueueNode * tmp = front;
	front = tmp->getNext();
	int frontInt = tmp->getMyInt();
	delete tmp;
	return frontInt;
}
<|endoftext|>