<commit_before>#include "SuiteHotkeyFunctions.h"

#ifdef DEBUG
#include <iostream>
#endif

#define LONG_PRESS_DURATION 3000	//3 sec (keep in mind that this define is compared with GetTickCount() that can have resolution up to 55ms)

KeyTriplet::KeyTriplet():
	OnModKey(std::bind(&KeyTriplet::OnCtrlAlt, this, std::placeholders::_1, std::placeholders::_2)),
	hk_binded_vk(VK_BACK), hk_binded_sc(0x0E), hk_long_press(false), hk_state(0), hk_down_tick(0), hk_up(true)
{}

bool KeyTriplet::OnCtrlAlt(DWORD vk, bool key_up)
{
	switch (vk) {
		case VK_LCONTROL:
		case VK_RCONTROL:
		case VK_CONTROL:
			//Ctrl
			if (key_up)	hk_state&=~0x1;
				else hk_state|=0x1;
			return true;
		case VK_LMENU:
		case VK_RMENU:
		case VK_MENU:
			//Alt
			if (key_up)	hk_state&=~0x2;
				else hk_state|=0x2;
			return true;
		default:
			return false;
	}
}

bool KeyTriplet::OnCtrlShift(DWORD vk, bool key_up)
{
	switch (vk) {
		case VK_LCONTROL:
		case VK_RCONTROL:
		case VK_CONTROL:
			//Ctrl
			if (key_up)	hk_state&=~0x1;
				else hk_state|=0x1;
			return true;
		case VK_LSHIFT:
		case VK_RSHIFT:
		case VK_SHIFT:
			//Shift
			if (key_up)	hk_state&=~0x2;
				else hk_state|=0x2;
			return true;
		default:
			return false;
	}
}

bool KeyTriplet::OnShiftAlt(DWORD vk, bool key_up)
{
	switch (vk) {
		case VK_LMENU:
		case VK_RMENU:
		case VK_MENU:
			//Alt
			if (key_up)	hk_state&=~0x1;
				else hk_state|=0x1;
			return true;
		case VK_LSHIFT:
		case VK_RSHIFT:
		case VK_SHIFT:
			//Shift
			if (key_up)	hk_state&=~0x2;
				else hk_state|=0x2;
			return true;
		default:
			return false;
	}
}

bool KeyTriplet::OnTargetKey(DWORD vk, DWORD sc, bool key_up)
{
	//For legacy reasons Break, Pause, PrtScn and Num[/] have scancodes shared respectively with ScrLock, NumLock, Num[*] and [?/]
	//So for these keys we should also compare virtual keys

	if (sc==hk_binded_sc) {
		switch (sc) {
			case 0x46:	//Break/ScrLock
			case 0x45:	//Pause/NumLock
			case 0x37:	//PrtScn/Num[*]
				if (vk!=hk_binded_vk)
					return false;
				break;
			case 0x35:	//Num[/]/[?/]
				//For Num[/]/[?/] it's a bit special
				//Num[/] always have VK=VK_DIVIDE and SC=0x35
				//[?/]'s SC is always 0x35 but VK is one of the OEM's VKs depending on currently selected layout
				if ((hk_binded_vk==VK_DIVIDE||vk==VK_DIVIDE)&&vk!=hk_binded_vk)
					return false;
				break;
		}
		//Don't forget that Ctrl+Pause=Break, Ctrl+ScrLock=Break, Ctrl+NumLock=Pause and Alt+PrtScn=SysRq
		//So hotkeys like Ctrl+Alt+Pause won't work because Ctrl+Alt+Break will be generated instead

		if (key_up)	hk_state&=~0x4;
			else hk_state|=0x4;

		return true;
	} else
		return false;
}

bool KeyTriplet::OnKeyPress(WPARAM wParam, KBDLLHOOKSTRUCT* kb_event)
{
	bool key_up=wParam==WM_KEYUP||wParam==WM_SYSKEYUP;

#ifdef DEBUG
	std::wcerr<<std::hex<<(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN?L"KEYDOWN":L"KEYUP")<<L" VK: "<<kb_event->vkCode<<L" SC: "<<kb_event->scanCode<<std::endl;
#endif

	if (OnModKey(kb_event->vkCode, key_up)||OnTargetKey(kb_event->vkCode, kb_event->scanCode, key_up)) {
		if (key_up) {
			if (!hk_up&&hk_long_press) {
				DWORD cur_tick=GetTickCount();
				if (cur_tick>=hk_down_tick) {	//Excludes moment of system timer wrap around after 49.7 days of uptime
					if (cur_tick-hk_down_tick>LONG_PRESS_DURATION) {
						MessageBeep(MB_ICONERROR);	//Long hotkey press (>LONG_PRESS_DURATION msec)
#ifdef DEBUG
						std::wcerr<<L"LONG PRESS KEYUP HOTKEY ENGAGED"<<std::endl;
#endif
					} else {
						MessageBeep(MB_ICONINFORMATION);	//Ordinary hotkey press
#ifdef DEBUG
						std::wcerr<<L"SINGLE PRESS KEYUP HOTKEY ENGAGED"<<std::endl;
#endif
					}
				}
			}
			hk_up=true;
		} else if (hk_state==0x7) {
			if (hk_up) {
				hk_up=false;
				if (hk_long_press)
					hk_down_tick=GetTickCount();
				else {
					MessageBeep(MB_ICONINFORMATION);	//Ordinary hotkey press
#ifdef DEBUG
					std::wcerr<<L"SINGLE PRESS KEYDOWN HOTKEY ENGAGED"<<std::endl;
#endif
				}
			}
			return true;
		}
	}

	return false;
}

bool BindKey(HWND dlg_hwnd, UINT bind_wm, WPARAM wParam, KBDLLHOOKSTRUCT* kb_event)
{
	if (wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN)
#ifdef DEBUG
		std::wcerr<<std::hex<<"KEYDOWN VK: "<<kb_event->vkCode<<L" SC: "<<kb_event->scanCode<<std::endl;
#endif
		//Ignoring Ctrl, Alt and Shift
		switch (kb_event->vkCode) {
			case VK_LMENU:
			case VK_RMENU:
			case VK_MENU:
			case VK_LSHIFT:
			case VK_RSHIFT:
			case VK_SHIFT:
			case VK_LCONTROL:
			case VK_RCONTROL:
			case VK_CONTROL:
				break;
			default:
				PostMessage(dlg_hwnd, bind_wm, kb_event->vkCode, kb_event->scanCode);
				return true;
		}
	return false;
}
<commit_msg>Macroses and comments<commit_after>#include "SuiteHotkeyFunctions.h"

#ifdef DEBUG
#include <iostream>
#endif

#define FLAG_HK_1ST	(1<<0)
#define FLAG_HK_2ND	(1<<1)
#define FLAG_HK_3RD	(1<<2)
#define FLAG_HK_ALL	(FLAG_HK_1ST|FLAG_HK_2ND|FLAG_HK_3RD)
#define LONG_PRESS_DURATION 3000	//3 sec (keep in mind that this define is compared with GetTickCount() that can have resolution up to 55ms)

KeyTriplet::KeyTriplet():
	OnModKey(std::bind(&KeyTriplet::OnCtrlAlt, this, std::placeholders::_1, std::placeholders::_2)),
	hk_binded_vk(VK_BACK), hk_binded_sc(0x0E), hk_long_press(false), hk_state(0), hk_down_tick(0), hk_up(true)
{}

bool KeyTriplet::OnCtrlAlt(DWORD vk, bool key_up)
{
	switch (vk) {
		case VK_LCONTROL:
		case VK_RCONTROL:
		case VK_CONTROL:
			//Ctrl
			if (key_up)	hk_state&=~FLAG_HK_1ST;
				else hk_state|=FLAG_HK_1ST;
			return true;
		case VK_LMENU:
		case VK_RMENU:
		case VK_MENU:
			//Alt
			if (key_up)	hk_state&=~FLAG_HK_2ND;
				else hk_state|=FLAG_HK_2ND;
			return true;
		default:
			return false;
	}
}

bool KeyTriplet::OnCtrlShift(DWORD vk, bool key_up)
{
	switch (vk) {
		case VK_LCONTROL:
		case VK_RCONTROL:
		case VK_CONTROL:
			//Ctrl
			if (key_up)	hk_state&=~FLAG_HK_1ST;
				else hk_state|=FLAG_HK_1ST;
			return true;
		case VK_LSHIFT:
		case VK_RSHIFT:
		case VK_SHIFT:
			//Shift
			if (key_up)	hk_state&=~FLAG_HK_2ND;
				else hk_state|=FLAG_HK_2ND;
			return true;
		default:
			return false;
	}
}

bool KeyTriplet::OnShiftAlt(DWORD vk, bool key_up)
{
	switch (vk) {
		case VK_LMENU:
		case VK_RMENU:
		case VK_MENU:
			//Alt
			if (key_up)	hk_state&=~FLAG_HK_1ST;
				else hk_state|=FLAG_HK_1ST;
			return true;
		case VK_LSHIFT:
		case VK_RSHIFT:
		case VK_SHIFT:
			//Shift
			if (key_up)	hk_state&=~FLAG_HK_2ND;
				else hk_state|=FLAG_HK_2ND;
			return true;
		default:
			return false;
	}
}

bool KeyTriplet::OnTargetKey(DWORD vk, DWORD sc, bool key_up)
{
	//For legacy reasons Break, Pause, PrtScn and Num[/] have scancodes shared respectively with ScrLock, NumLock, Num[*] and [?/]
	//So for these keys we should also compare virtual keys to distinguish them from one another

	if (sc==hk_binded_sc) {
		switch (sc) {
			case 0x46:	//Break/ScrLock
			case 0x45:	//Pause/NumLock
			case 0x37:	//PrtScn/Num[*]
				if (vk!=hk_binded_vk)
					return false;
				break;
			case 0x35:	//Num[/]/[?/]
				//For Num[/]/[?/] it's a bit special
				//Num[/] always have VK=VK_DIVIDE and SC=0x35
				//[?/]'s SC is always 0x35 but VK is one of the OEM's VKs depending on currently selected layout
				if ((hk_binded_vk==VK_DIVIDE||vk==VK_DIVIDE)&&vk!=hk_binded_vk)
					return false;
				break;
		}
		//Don't forget that Ctrl+Pause=Break, Ctrl+ScrLock=Break, Ctrl+NumLock=Pause and Alt+PrtScn=SysRq
		//So hotkeys like Ctrl+Alt+Pause won't work because Ctrl+Alt+Break will be generated instead

		if (key_up)	hk_state&=~FLAG_HK_3RD;
			else hk_state|=FLAG_HK_3RD;

		return true;
	} else
		return false;
}

bool KeyTriplet::OnKeyPress(WPARAM wParam, KBDLLHOOKSTRUCT* kb_event)
{
	bool key_up=wParam==WM_KEYUP||wParam==WM_SYSKEYUP;

#ifdef DEBUG
	std::wcerr<<std::hex<<(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN?L"KEYDOWN":L"KEYUP")<<L" VK: "<<kb_event->vkCode<<L" SC: "<<kb_event->scanCode<<std::endl;
#endif

	if (OnModKey(kb_event->vkCode, key_up)||OnTargetKey(kb_event->vkCode, kb_event->scanCode, key_up)) {
		if (key_up) {
			if (!hk_up&&hk_long_press) {
				DWORD cur_tick=GetTickCount();
				if (cur_tick>=hk_down_tick) {	//Excludes moment of system timer wrap around after 49.7 days of uptime
					if (cur_tick-hk_down_tick>LONG_PRESS_DURATION) {
						MessageBeep(MB_ICONERROR);	//Long hotkey press (>LONG_PRESS_DURATION msec)
#ifdef DEBUG
						std::wcerr<<L"LONG PRESS KEYUP HOTKEY ENGAGED"<<std::endl;
#endif
					} else {
						MessageBeep(MB_ICONINFORMATION);	//Ordinary hotkey press
#ifdef DEBUG
						std::wcerr<<L"SINGLE PRESS KEYUP HOTKEY ENGAGED"<<std::endl;
#endif
					}
				}
			}
			hk_up=true;
		} else if (hk_state==FLAG_HK_ALL) {
			if (hk_up) {
				hk_up=false;
				if (hk_long_press)
					hk_down_tick=GetTickCount();
				else {
					MessageBeep(MB_ICONINFORMATION);	//Ordinary hotkey press
#ifdef DEBUG
					std::wcerr<<L"SINGLE PRESS KEYDOWN HOTKEY ENGAGED"<<std::endl;
#endif
				}
			}
			return true;
		}
	}

	return false;
}

bool BindKey(HWND dlg_hwnd, UINT bind_wm, WPARAM wParam, KBDLLHOOKSTRUCT* kb_event)
{
	if (wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN)
#ifdef DEBUG
		std::wcerr<<std::hex<<"KEYDOWN VK: "<<kb_event->vkCode<<L" SC: "<<kb_event->scanCode<<std::endl;
#endif
		//Ignoring Ctrl, Alt and Shift
		switch (kb_event->vkCode) {
			case VK_LMENU:
			case VK_RMENU:
			case VK_MENU:
			case VK_LSHIFT:
			case VK_RSHIFT:
			case VK_SHIFT:
			case VK_LCONTROL:
			case VK_RCONTROL:
			case VK_CONTROL:
				break;
			default:
				PostMessage(dlg_hwnd, bind_wm, kb_event->vkCode, kb_event->scanCode);
				return true;
		}
	return false;
}
<|endoftext|>


<commit_before>/*MIT License

Copyright (c) 2017 TU Ilmenau, Systems and Software Engineering Group

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.
*/

/*
 * Simple C++UML Example. In this example simple UML-Elements (Class, Model, Operation,...) will be created. Some model contet will be printed out followed by the informations of metamodel and meta-metamodel.
 */

#include <iostream>

#include "abstractDataTypes/SubsetUnion.hpp"
#include "uml/umlFactory.hpp"
#include "uml/umlPackage.hpp"
#include "uml/Class.hpp"
#include "uml/Model.hpp"
#include "uml/Operation.hpp"
#include "uml/InstanceSpecification.hpp"

#include "ecore/EClass.hpp"
#include "ecore/EOperation.hpp"

#include "umlReflection/UMLPackage.hpp"

using namespace std;

int main()
{
    //#############  Create simple UML model  #############
    std::shared_ptr<uml::umlFactory> factory = uml::umlFactory::eInstance();
    std::shared_ptr<uml::umlPackage> package = uml::umlPackage::eInstance();

    std::shared_ptr<uml::Model> p = factory->createModel();
    p->setName("Model");

    std::shared_ptr<uml::Class> c = factory->createClass_in_Package(p);
    c->setName("Class1");

    //create an operation
    std::shared_ptr<uml::Operation> o = factory->createOperation_in_Class(c);
    o->setName("do");

    //use a string to create a class in a Package
    std::shared_ptr<ecore::EObject> a = factory->create("Class", p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class2");

    //use a Package::MetaElement-ID to create a class
    a = factory->create(uml::umlPackage::CLASS_CLASS, p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class3");

    //use a MetaClass to create a class
    a = factory->create(c->eClass(), p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class4");
    c->setPackage(p);

    //use a umlPackage MetaClass to create a class
    a = factory->create(package->getClass_Class(), p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class5");
    //

    //create an UML-Objekt (InstanceSpecification) of Class1
    std::shared_ptr<uml::InstanceSpecification> i = factory->createInstanceSpecification_in_Owner(p);
    i->setName("o");
    std::shared_ptr<Bag<uml::Classifier>> t = i->getClassifier();
    t->push_back(c); //set Type to Class1

    //#############  Print model content  #############

    cout << "______________ Model ____________" << endl;
	std::shared_ptr<Bag<uml::PackageableElement>> elements = p->getPackagedElement();
    for(std::shared_ptr<uml::PackageableElement>it : *elements)
    {
        // optional type check using UML Metamodel
        std::shared_ptr<ecore::EClass> uc = uml::umlPackage::eInstance()->getClass_Class();
        if(it->eClass() == uc->eClass())
        {
            cout << it->getName() << " is a Class"<< endl;
            std::shared_ptr<uml::Class> itC = std::dynamic_pointer_cast<uml::Class>(it); // It is certainly an uml::Class
			std::shared_ptr<Bag<uml::Operation>> opList = itC->getOwnedOperation();
            for(std::shared_ptr<uml::Operation>it : *opList)
            {
                cout << it->getName() << endl;
            }
        }
        else
        {
            cout << it->getName() << " is a " << it->eClass()->getName() << endl;
        }
    }

    cout << "______________ Ecore MetaModel ____________" << endl;

    std::shared_ptr<ecore::EClass> mc = c->eClass(); // UML is defined with ecore
    cout << mc->getName() << " :" << endl;
	std::shared_ptr<Bag<ecore::EOperation>> opList = mc->getEAllOperations();
    for(std::shared_ptr<ecore::EOperation> it : *opList)
    {
        cout << it->getName() << endl;
    }

    cout << "___________ Ecore MetaMetaModel _______________" << endl;

    std::shared_ptr<ecore::EClass> mmc = mc->eClass();
    cout << mmc->getName() << " :" << endl;

	std::shared_ptr<Bag<ecore::EOperation>> opList2 = mmc->getEAllOperations();
    for(std::shared_ptr<ecore::EOperation> it : *opList2)
    {
        cout << it->getName() << endl;
    }

    return 0;
}
<commit_msg>[examples] fixed UML example concering new create methods<commit_after>/*MIT License

Copyright (c) 2017 TU Ilmenau, Systems and Software Engineering Group

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.
*/

/*
 * Simple C++UML Example. In this example simple UML-Elements (Class, Model, Operation,...) will be created. Some model contet will be printed out followed by the informations of metamodel and meta-metamodel.
 */

#include <iostream>

#include "abstractDataTypes/SubsetUnion.hpp"
#include "uml/umlFactory.hpp"
#include "uml/umlPackage.hpp"
#include "uml/Class.hpp"
#include "uml/Model.hpp"
#include "uml/Operation.hpp"
#include "uml/InstanceSpecification.hpp"

#include "ecore/EClass.hpp"
#include "ecore/EOperation.hpp"

#include "umlReflection/UMLPackage.hpp"

using namespace std;

int main()
{
    //#############  Create simple UML model  #############
    std::shared_ptr<uml::umlFactory> factory = uml::umlFactory::eInstance();
    std::shared_ptr<uml::umlPackage> package = uml::umlPackage::eInstance();

    std::shared_ptr<uml::Model> p = factory->createModel();
    p->setName("Model");

    std::shared_ptr<uml::Class> c = factory->createClass_as_ownedType_in_Package(p);
    c->setName("Class1");

    //create an operation
    std::shared_ptr<uml::Operation> o = factory->createOperation_as_ownedOperation_in_Class(c);
    o->setName("do");

    //use a string to create a class in a Package
    std::shared_ptr<ecore::EObject> a = factory->create("Class", p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class2");

    //use a Package::MetaElement-ID to create a class
    a = factory->create(uml::umlPackage::CLASS_CLASS, p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class3");

    //use a MetaClass to create a class
    a = factory->create(c->eClass(), p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class4");
    c->setPackage(p);

    //use a umlPackage MetaClass to create a class
    a = factory->create(package->getClass_Class(), p, package->TYPE_ATTRIBUTE_PACKAGE);
    c = std::dynamic_pointer_cast<uml::Class>(a);
    c->setName("Class5");
    //

    //create an UML-Objekt (InstanceSpecification) of Class1
    std::shared_ptr<uml::InstanceSpecification> i = factory->createInstanceSpecification_as_ownedElement_in_Element(p);
    i->setName("o");
    std::shared_ptr<Bag<uml::Classifier>> t = i->getClassifier();
    t->push_back(c); //set Type to Class1

    //#############  Print model content  #############

    cout << "______________ Model ____________" << endl;
	std::shared_ptr<Bag<uml::PackageableElement>> elements = p->getPackagedElement();
    for(std::shared_ptr<uml::PackageableElement>it : *elements)
    {
        // optional type check using UML Metamodel
        std::shared_ptr<ecore::EClass> uc = uml::umlPackage::eInstance()->getClass_Class();
        if(it->eClass() == uc->eClass())
        {
            cout << it->getName() << " is a Class"<< endl;
            std::shared_ptr<uml::Class> itC = std::dynamic_pointer_cast<uml::Class>(it); // It is certainly an uml::Class
			std::shared_ptr<Bag<uml::Operation>> opList = itC->getOwnedOperation();
            for(std::shared_ptr<uml::Operation>it : *opList)
            {
                cout << it->getName() << endl;
            }
        }
        else
        {
            cout << it->getName() << " is a " << it->eClass()->getName() << endl;
        }
    }

    cout << "______________ Ecore MetaModel ____________" << endl;

    std::shared_ptr<ecore::EClass> mc = c->eClass(); // UML is defined with ecore
    cout << mc->getName() << " :" << endl;
	std::shared_ptr<Bag<ecore::EOperation>> opList = mc->getEAllOperations();
    for(std::shared_ptr<ecore::EOperation> it : *opList)
    {
        cout << it->getName() << endl;
    }

    cout << "___________ Ecore MetaMetaModel _______________" << endl;

    std::shared_ptr<ecore::EClass> mmc = mc->eClass();
    cout << mmc->getName() << " :" << endl;

	std::shared_ptr<Bag<ecore::EOperation>> opList2 = mmc->getEAllOperations();
    for(std::shared_ptr<ecore::EOperation> it : *opList2)
    {
        cout << it->getName() << endl;
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * mpu6050_node.cpp
 * Copyright (c) 2017, Robot Mitya.
 * 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 Robot Mitya 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.
 *
 *  Created on: Dec 3, 2017
 *      Author: Dmitry Dzakhov
 */

#include <ros/ros.h>
#include <sensor_msgs/Imu.h>
#include "std_msgs/String.h"
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include "consts.h"
#include "mpu6050_helper.h"
#include "madgwick.h"

#define VALUES_TO_CALIBRATE 1000

class Mpu6050Node
{
public:
  Mpu6050Node();
  void readImuData(float *vX, float *vY, float *vZ, float *aX, float *aY, float *aZ);
  bool performingCalibration(float vX, float vY, float vZ);

  void fillImuMessage(const sensor_msgs::ImuPtr& msg, float vX, float vY, float vZ, float aX, float aY, float aZ);
  void publishImuMessage(const sensor_msgs::ImuPtr& msg);
  void center();
private:
  int i2cAddress_;
  int fileDescriptor_;
  uint8_t buffer_[14];
  float gyroFactor_;

  float readWord2c(int addr);

  // Topic RM_IMU_TOPIC_NAME ('imu') publisher:
  ros::Publisher imuPublisher_;

  ros::Subscriber imuInputSubscriber_;
  void imuInputCallback(const std_msgs::StringConstPtr& msg);

  MpuHelper mpuHelper_;

  ros::Time prevStamp_;
  uint32_t prevSeq_;
  MadgwickImu madgwick_;

  uint32_t seq_;
};

const int PWR_MGMT_1 = 0x6B;

Mpu6050Node::Mpu6050Node()
{
  ros::NodeHandle privateNodeHandle("~");
  privateNodeHandle.param("i2c_address", i2cAddress_, 0x68);
//  privateNodeHandle.

  // Connect to device.
  fileDescriptor_ = wiringPiI2CSetup(i2cAddress_);
  if (fileDescriptor_ == -1)
  {
    ROS_ERROR("No i2c device found?");
    return;
  }
  // Device starts in sleep mode so wake it up.
  wiringPiI2CWriteReg16(fileDescriptor_, PWR_MGMT_1, 0);

  ros::NodeHandle nodeHandle(RM_NAMESPACE);
  imuPublisher_ = nodeHandle.advertise<sensor_msgs::Imu>(RM_HEAD_IMU_OUTPUT_TOPIC_NAME, 100);

  imuInputSubscriber_ = nodeHandle.subscribe(RM_HEAD_IMU_INPUT_TOPIC_NAME, 10, &Mpu6050Node::imuInputCallback, this);

  seq_ = 0;
  gyroFactor_ = 3.141592654f / 180 / 131;

  prevStamp_ = ros::Time::now();
  prevSeq_ = 0;
  madgwick_.center();
}

float Mpu6050Node::readWord2c(int addr)
{
  uint16_t val = wiringPiI2CReadReg16(fileDescriptor_, addr);
  uint16_t swappedVal = (val >> 8) | (val << 8);
  return float((swappedVal >= 0x8000) ? -((65535 - swappedVal) + 1) : swappedVal);
}

void Mpu6050Node::readImuData(float *vX, float *vY, float *vZ, float *aX, float *aY, float *aZ)
{
  // Read gyroscope values.
  // At default sensitivity of 250deg/s we need to scale by 131.
  *vX = -readWord2c(0x47) * gyroFactor_; // -z (caused by chip orientation in robot)
  *vY = readWord2c(0x45) * gyroFactor_;  // y
  *vZ = readWord2c(0x43) * gyroFactor_;  // x (caused by chip orientation in robot)

  // Read accelerometer values.
  // At default sensitivity of 2g we need to scale by 16384.
  // Note: at "level" x = y = 0 but z = 1 (i.e. gravity)
  // But! Imu message documentations say acceleration should be in m/2 so need to *9.807
  const float la_rescale = 16384.0 / 9.807;
  *aX = -readWord2c(0x3f) / la_rescale; // -z (caused by chip orientation in robot)
  *aY = readWord2c(0x3d) / la_rescale; // y
  *aZ = readWord2c(0x3b) / la_rescale; // x (caused by chip orientation in robot)

  mpuHelper_.correctMpuData(vX, vY, vZ);
}

void Mpu6050Node::fillImuMessage(const sensor_msgs::ImuPtr& msg, float vX, float vY, float vZ, float aX, float aY, float aZ)
{
  msg->header.stamp = ros::Time::now();
  msg->header.seq = seq_++;
  msg->header.frame_id = '0';  // no frame

  msg->angular_velocity.x = vX;
  msg->angular_velocity.y = vY;
  msg->angular_velocity.z = vZ;

  msg->linear_acceleration.x = aX;
  msg->linear_acceleration.y = aY;
  msg->linear_acceleration.z = aZ;

  ros::Duration deltaTime = msg->header.stamp - prevStamp_;
  prevStamp_ = msg->header.stamp;
  madgwick_.update(deltaTime.toSec(), vX, vY, vZ, aX, aY, aZ);

  tf2Scalar qX, qY, qZ, qW;
  madgwick_.getQuaternion(qX, qY, qZ, qW);
  msg->orientation.x = qX;
  msg->orientation.y = qY;
  msg->orientation.z = qZ;
  msg->orientation.w = qW;
}

void Mpu6050Node::publishImuMessage(const sensor_msgs::ImuPtr& msg)
{
  imuPublisher_.publish(msg);
}

void Mpu6050Node::imuInputCallback(const std_msgs::StringConstPtr& msg)
{
  if (msg->data.compare("calibrate") == 0)
  {
    ROS_INFO("Starting to calibrate head IMU...");
    mpuHelper_.startCalibration();
    //madgwick_.center();
  }
  else if (msg->data.compare("center") == 0)
  {
    ROS_INFO("Center head IMU...");
    madgwick_.center();
  }
  else if (msg->data.compare("configuration") == 0)
  {
    uint8_t gyroConfig = wiringPiI2CReadReg8(fileDescriptor_, 27);
    uint8_t accConfig = wiringPiI2CReadReg8(fileDescriptor_, 28);
    ROS_INFO("GYRO_CONFIG (register 27) = %d    ACCEL_CONFIG (register 28) = %d", gyroConfig, accConfig);
  }
  else
  {
    ROS_ERROR("%s.%s: Unknown command \"%s\"", RM_MPU6050_NODE_NAME, RM_HEAD_IMU_INPUT_TOPIC_NAME, msg->data.c_str());
  }
}

bool Mpu6050Node::performingCalibration(float vX, float vY, float vZ)
{
  return mpuHelper_.processCalibration(vX, vY, vZ);
}

void Mpu6050Node::center()
{
  madgwick_.center();
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, RM_MPU6050_NODE_NAME);

  Mpu6050Node mpu6050Node;
  sensor_msgs::ImuPtr imuPrt(new sensor_msgs::Imu());

  float vX, vY, vZ, aX, aY, aZ;
  ros::Rate rate(50);  // hz
  bool prevPerformingCalibration = false;
  bool performingCalibration;
  while(ros::ok())
  {
    mpu6050Node.readImuData(&vX, &vY, &vZ, &aX, &aY, &aZ);

    performingCalibration = mpu6050Node.performingCalibration(vX, vY, vZ);
    if (!performingCalibration)
    {
      mpu6050Node.fillImuMessage(imuPrt, vX, vY, vZ, aX, aY, aZ);
      mpu6050Node.publishImuMessage(imuPrt);
    }
    else if (prevPerformingCalibration && !performingCalibration)
    {
      // Calibration is over:
      mpu6050Node.center();
    }
    prevPerformingCalibration = performingCalibration;

    ros::spinOnce();
    rate.sleep();
  }
  return 0;
}
<commit_msg>#12 IMU: mpu6050_node calibration fix<commit_after>/*
 * mpu6050_node.cpp
 * Copyright (c) 2017, Robot Mitya.
 * 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 Robot Mitya 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.
 *
 *  Created on: Dec 3, 2017
 *      Author: Dmitry Dzakhov
 */

#include <ros/ros.h>
#include <sensor_msgs/Imu.h>
#include "std_msgs/String.h"
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include "consts.h"
#include "mpu6050_helper.h"
#include "madgwick.h"

#define VALUES_TO_CALIBRATE 1000

class Mpu6050Node
{
public:
  Mpu6050Node();
  void readImuData(float *vX, float *vY, float *vZ, float *aX, float *aY, float *aZ);
  bool performingCalibration(float vX, float vY, float vZ);

  void fillImuMessage(const sensor_msgs::ImuPtr& msg, float vX, float vY, float vZ, float aX, float aY, float aZ);
  void publishImuMessage(const sensor_msgs::ImuPtr& msg);
  void center();
private:
  int i2cAddress_;
  int fileDescriptor_;
  uint8_t buffer_[14];
  float gyroFactor_;

  float readWord2c(int addr);

  // Topic RM_IMU_TOPIC_NAME ('imu') publisher:
  ros::Publisher imuPublisher_;

  ros::Subscriber imuInputSubscriber_;
  void imuInputCallback(const std_msgs::StringConstPtr& msg);

  MpuHelper mpuHelper_;

  ros::Time prevStamp_;
  uint32_t prevSeq_;
  MadgwickImu madgwick_;

  uint32_t seq_;
};

const int PWR_MGMT_1 = 0x6B;

Mpu6050Node::Mpu6050Node()
{
  ros::NodeHandle privateNodeHandle("~");
  privateNodeHandle.param("i2c_address", i2cAddress_, 0x68);
//  privateNodeHandle.

  // Connect to device.
  fileDescriptor_ = wiringPiI2CSetup(i2cAddress_);
  if (fileDescriptor_ == -1)
  {
    ROS_ERROR("No i2c device found?");
    return;
  }
  // Device starts in sleep mode so wake it up.
  wiringPiI2CWriteReg16(fileDescriptor_, PWR_MGMT_1, 0);

  ros::NodeHandle nodeHandle(RM_NAMESPACE);
  imuPublisher_ = nodeHandle.advertise<sensor_msgs::Imu>(RM_HEAD_IMU_OUTPUT_TOPIC_NAME, 100);

  imuInputSubscriber_ = nodeHandle.subscribe(RM_HEAD_IMU_INPUT_TOPIC_NAME, 10, &Mpu6050Node::imuInputCallback, this);

  seq_ = 0;
  gyroFactor_ = 3.141592654f / 180 / 131;

  prevStamp_ = ros::Time::now();
  prevSeq_ = 0;
  madgwick_.center();
}

float Mpu6050Node::readWord2c(int addr)
{
  uint16_t val = wiringPiI2CReadReg16(fileDescriptor_, addr);
  uint16_t swappedVal = (val >> 8) | (val << 8);
  return float((swappedVal >= 0x8000) ? -((65535 - swappedVal) + 1) : swappedVal);
}

void Mpu6050Node::readImuData(float *vX, float *vY, float *vZ, float *aX, float *aY, float *aZ)
{
  // Read gyroscope values.
  // At default sensitivity of 250deg/s we need to scale by 131.
  *vX = -readWord2c(0x47) * gyroFactor_; // -z (caused by chip orientation in robot)
  *vY = readWord2c(0x45) * gyroFactor_;  // y
  *vZ = readWord2c(0x43) * gyroFactor_;  // x (caused by chip orientation in robot)

  // Read accelerometer values.
  // At default sensitivity of 2g we need to scale by 16384.
  // Note: at "level" x = y = 0 but z = 1 (i.e. gravity)
  // But! Imu message documentations say acceleration should be in m/2 so need to *9.807
  const float la_rescale = 16384.0 / 9.807;
  *aX = -readWord2c(0x3f) / la_rescale; // -z (caused by chip orientation in robot)
  *aY = readWord2c(0x3d) / la_rescale; // y
  *aZ = readWord2c(0x3b) / la_rescale; // x (caused by chip orientation in robot)

  mpuHelper_.correctMpuData(vX, vY, vZ);
}

void Mpu6050Node::fillImuMessage(const sensor_msgs::ImuPtr& msg, float vX, float vY, float vZ, float aX, float aY, float aZ)
{
  msg->header.stamp = ros::Time::now();
  msg->header.seq = seq_++;
  msg->header.frame_id = '0';  // no frame

  msg->angular_velocity.x = vX;
  msg->angular_velocity.y = vY;
  msg->angular_velocity.z = vZ;

  msg->linear_acceleration.x = aX;
  msg->linear_acceleration.y = aY;
  msg->linear_acceleration.z = aZ;

  ros::Duration deltaTime = msg->header.stamp - prevStamp_;
  prevStamp_ = msg->header.stamp;
  madgwick_.update(deltaTime.toSec(), vX, vY, vZ, aX, aY, aZ);

  tf2Scalar qX, qY, qZ, qW;
  madgwick_.getQuaternion(qX, qY, qZ, qW);
  msg->orientation.x = qX;
  msg->orientation.y = qY;
  msg->orientation.z = qZ;
  msg->orientation.w = qW;
}

void Mpu6050Node::publishImuMessage(const sensor_msgs::ImuPtr& msg)
{
  imuPublisher_.publish(msg);
}

void Mpu6050Node::imuInputCallback(const std_msgs::StringConstPtr& msg)
{
  if (msg->data.compare("calibrate") == 0)
  {
    ROS_INFO("Starting to calibrate head IMU...");
    mpuHelper_.startCalibration();
    //madgwick_.center();
  }
  else if (msg->data.compare("center") == 0)
  {
    ROS_INFO("Center head IMU...");
    madgwick_.center();
  }
  else if (msg->data.compare("configuration") == 0)
  {
    uint8_t gyroConfig = wiringPiI2CReadReg8(fileDescriptor_, 27);
    uint8_t accConfig = wiringPiI2CReadReg8(fileDescriptor_, 28);
    ROS_INFO("GYRO_CONFIG (register 27) = %d    ACCEL_CONFIG (register 28) = %d", gyroConfig, accConfig);
  }
  else
  {
    ROS_ERROR("%s.%s: Unknown command \"%s\"", RM_MPU6050_NODE_NAME, RM_HEAD_IMU_INPUT_TOPIC_NAME, msg->data.c_str());
  }
}

bool Mpu6050Node::performingCalibration(float vX, float vY, float vZ)
{
  return mpuHelper_.processCalibration(vX, vY, vZ);
}

void Mpu6050Node::center()
{
  madgwick_.center();
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, RM_MPU6050_NODE_NAME);

  Mpu6050Node mpu6050Node;
  sensor_msgs::ImuPtr imuPrt(new sensor_msgs::Imu());

  float vX, vY, vZ, aX, aY, aZ;
  ros::Rate rate(50);  // hz
  bool prevPerformingCalibration = false;
  bool performingCalibration;
  while(ros::ok())
  {
    mpu6050Node.readImuData(&vX, &vY, &vZ, &aX, &aY, &aZ);

    performingCalibration = mpu6050Node.performingCalibration(vX, vY, vZ);
    if (!performingCalibration)
    {
      if (prevPerformingCalibration)
      {
        // Calibration is over:
        mpu6050Node.center();
      }
      else
      {
        mpu6050Node.fillImuMessage(imuPrt, vX, vY, vZ, aX, aY, aZ);
        mpu6050Node.publishImuMessage(imuPrt);
      }
    }
    prevPerformingCalibration = performingCalibration;

    ros::spinOnce();
    rate.sleep();
  }
  return 0;
}
<|endoftext|>


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

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

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

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

#include <memory>
#include <string>
#include <utility>

#include "llvm/Support/FormatVariadic.h"
#include "mlir/IR/TypeUtilities.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Pass/PassRegistry.h"  // from @llvm-project
#include "mlir/Transforms/RegionUtils.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_device.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/lower_tf.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"
#include "tensorflow/compiler/mlir/xla/transforms/passes.h"
#include "tensorflow/core/lib/monitoring/gauge.h"

namespace mlir {
namespace TFDevice {

namespace {

constexpr char kXlaOutsideCompilationAttr[] = "_xla_outside_compilation";
constexpr char kAllowSoftPlacementAttr[] = "allow_soft_placement";

auto* auto_outside_compilation_gauge =
    tensorflow::monitoring::Gauge<bool, 0>::New(
        "/tensorflow/core/use_auto_outside_compilation",
        "Tracks if auto outside compilation is enabled");

// This pass marks unsupported ops in a device cluster with
// `_xla_outside_compilation` attribute so the operations will run on the host
// instead of the device.  Unsupported ops are ops that can not be code
// generated to run on the device for the cluster.
struct MarkOpsForOutsideCompilation
    : public PassWrapper<MarkOpsForOutsideCompilation,
                         OperationPass<ModuleOp>> {
  void runOnOperation() override;
};

// Adds any canonicalization patterns to list of supported `patterns`.
// TODO(b/161726307): Move or import the relevant patterns to LowerTF pass and
// remove this.
void AddCanonicalizationPatterns(MLIRContext* context,
                                 OwningRewritePatternList* patterns) {
  for (auto* op : context->getRegisteredOperations())
    op->getCanonicalizationPatterns(*patterns, context);
}

// TODO(b/159128666): Check the control flow legalization passes instead once
// added.
void AddSupportedControlFlowOps(MLIRContext* context,
                                llvm::DenseSet<OperationName>* supported_ops) {
  supported_ops->insert(
      OperationName(TF::IfRegionOp::getOperationName(), context));
  supported_ops->insert(
      OperationName(TF::WhileRegionOp::getOperationName(), context));
  supported_ops->insert(
      OperationName(TF::YieldOp::getOperationName(), context));
}

// These embedding ops are rewritten when running TPUCompileOp.
void AddRewrittenEmbeddingOps(MLIRContext* context,
                              llvm::DenseSet<OperationName>* supported_ops) {
  supported_ops->insert(OperationName(
      TF::RecvTPUEmbeddingActivationsOp::getOperationName(), context));
  supported_ops->insert(OperationName(
      TF::SendTPUEmbeddingGradientsOp::getOperationName(), context));
}

// Stack, TensorList and TensorArray ops are rewritten during the second phase
// of the bridge (compilation of TPUCompile op). They would not match any
// legalization/canonicalization pattern and have to be manually added to the
// list of supported ops.
void AddRewrittenCompositeOps(MLIRContext* context,
                              llvm::DenseSet<OperationName>* supported_ops) {
#define GET_OPERATION_NAME(op) OperationName(op::getOperationName(), context)
  llvm::SmallDenseSet<OperationName, 32> allowlist_ops = {
      // Stack ops.
      GET_OPERATION_NAME(TF::StackV2Op),
      GET_OPERATION_NAME(TF::StackPushV2Op),
      GET_OPERATION_NAME(TF::StackPopV2Op),
      // Tensor Array ops.
      GET_OPERATION_NAME(TF::TensorArrayV3Op),
      GET_OPERATION_NAME(TF::TensorArrayReadV3Op),
      GET_OPERATION_NAME(TF::TensorArrayWriteV3Op),
      GET_OPERATION_NAME(TF::TensorArrayConcatV3Op),
      GET_OPERATION_NAME(TF::TensorArraySplitV3Op),
      GET_OPERATION_NAME(TF::TensorArraySizeV3Op),
      GET_OPERATION_NAME(TF::TensorArrayGradV3Op),
      GET_OPERATION_NAME(TF::TensorArrayGatherV3Op),
      GET_OPERATION_NAME(TF::TensorArrayScatterV3Op),
      GET_OPERATION_NAME(TF::TensorListFromTensorOp),
      // Tensor List Ops.
      GET_OPERATION_NAME(TF::EmptyTensorListOp),
      GET_OPERATION_NAME(TF::TensorListReserveOp),
      GET_OPERATION_NAME(TF::TensorListFromTensorOp),
      GET_OPERATION_NAME(TF::TensorListPushBackOp),
      GET_OPERATION_NAME(TF::TensorListPopBackOp),
      GET_OPERATION_NAME(TF::TensorListGetItemOp),
      GET_OPERATION_NAME(TF::TensorListSetItemOp),
      GET_OPERATION_NAME(TF::TensorListLengthOp),
      GET_OPERATION_NAME(TF::TensorListElementShapeOp),
      GET_OPERATION_NAME(TF::TensorListGatherOp),
      GET_OPERATION_NAME(TF::TensorListScatterIntoExistingListOp),
  };
#undef GET_OPERATION_NAME

  supported_ops->insert(allowlist_ops.begin(), allowlist_ops.end());
}

bool IsStringType(Type type) {
  if (type.isa<TF::StringType>()) return true;

  auto sub_type = type.dyn_cast<TF::TensorFlowTypeWithSubtype>();
  if (!sub_type) return false;

  bool has_string = llvm::any_of(sub_type.GetSubtypes(), [](TensorType type) {
    return type.getElementType().isa<TF::StringType>();
  });
  return has_string;
}

bool HasStringOperand(Operation& op) {
  for (auto operand : op.getOperands()) {
    auto operand_type = getElementTypeOrSelf(operand);
    if (IsStringType(operand_type)) return true;
  }
  return false;
}

bool HasStringResult(Operation& op) {
  for (auto result : op.getResults()) {
    auto result_type = getElementTypeOrSelf(result);
    if (IsStringType(result_type)) return true;
  }
  return false;
}

bool MatchesPattern(Operation& op,
                    const llvm::DenseSet<OperationName>& supported_ops) {
  return (supported_ops.contains(op.getName()));
}

// Checks if the op is supported inside of a device cluster.  Ops not
// in `tf_dialect` are considered supported.
bool IsSupportedOp(Operation& op,
                   const llvm::DenseSet<OperationName>& supported_ops,
                   const Dialect* tf_dialect) {
  if (op.getDialect() != tf_dialect)
    return true;
  // Assert has a legalization that later removes it so we don't want to outside
  // compile it ever for performance reasons.
  if (llvm::isa<TF::AssertOp>(op)) return true;
  return !HasStringOperand(op) && !HasStringResult(op) &&
         (MatchesPattern(op, supported_ops) ||
          mhlo::IsOpAllowedTf2XlaFallback(&op));
}

// Checks all regions of `op` for captured string operands.
bool HasCapturedStringOperand(Operation* op) {
  bool string_operand = false;
  for (auto& region : op->getRegions()) {
    mlir::visitUsedValuesDefinedAbove(
        region, region, [&](mlir::OpOperand* operand) {
          if (getElementTypeOrSelf(operand->get()).isa<TF::StringType>())
            string_operand = true;
        });
    if (string_operand) return string_operand;
  }
  return string_operand;
}

// Marks uncompilable ops that are in `tf_dialect` for outside compilation.
LogicalResult MarkUncompilableOps(
    const Dialect* tf_dialect, Block* block,
    llvm::DenseSet<OperationName>& supported_ops) {
  // Automatically marked ops for outside compilation have
  // `_xla_outside_compilation` attribute value of "auto" plus
  // an increasing counter.  Manually marked ops for outside compilation only
  // have an increasing counteri for the attribute value.  Therefore there is no
  // collision in
  // `_xla_outside_compilation` attribute between automatically and manually
  // marking ops.
  int outside_compiled_cluster_counter = 0;
  block->walk([&](Operation* op) {
    if (!IsSupportedOp(*op, supported_ops, tf_dialect)) {
      op->setAttr(
          kXlaOutsideCompilationAttr,
          StringAttr::get(
              llvm::formatv("auto{0}", outside_compiled_cluster_counter).str(),
              op->getContext()));
      outside_compiled_cluster_counter++;
    }
  });
  if (outside_compiled_cluster_counter > 0) {
    auto_outside_compilation_gauge->GetCell()->Set(true);
  }
  return success();
}

// Unmarks outside compilation for any op that has parents already
// marked for outside compilation since the child will be extracted
// anyways.
void UnmarkChildren(Block* block) {
  block->walk([&](Operation* op) {
    if (!op->getAttrOfType<StringAttr>(kXlaOutsideCompilationAttr)) return;
    Operation* iter_op = op;
    bool remove_attr = false;
    while (auto* parent_op = iter_op->getParentOp()) {
      if (parent_op->getAttrOfType<StringAttr>(kXlaOutsideCompilationAttr)) {
        remove_attr = true;
        break;
      }
      iter_op = parent_op;
    }
    if (remove_attr) op->removeAttr(kXlaOutsideCompilationAttr);
  });
}

void MarkOpsForOutsideCompilation::runOnOperation() {
  auto module = getOperation();
  const Dialect* tf_dialect = getContext().getLoadedDialect("tf");
  if (!tf_dialect) {
    getOperation().emitError() << "'tf' dialect is not registered";
    return signalPassFailure();
  }
  OwningRewritePatternList patterns;
  mhlo::PopulateLegalizeTfPatterns(module.getContext(), &patterns);
  TF::PopulateLoweringTFPatterns(module.getContext(), &patterns);
  AddCanonicalizationPatterns(module.getContext(), &patterns);

  // `supported_ops` contains the name of all of the ops that can potentially be
  // lowered into HLO on the device. This doesn't always mean that the op can
  // be lowered in the future passes but if the op is not in this set, it can't
  // be lowered in a subsequent pass.
  llvm::DenseSet<OperationName> supported_ops;
  for (auto& pattern : patterns) {
    Optional<OperationName> root_kind = pattern->getRootKind();
    if (root_kind.hasValue()) supported_ops.insert(root_kind.getValue());
  }
  AddSupportedControlFlowOps(module.getContext(), &supported_ops);
  AddRewrittenEmbeddingOps(module.getContext(), &supported_ops);
  AddRewrittenCompositeOps(module.getContext(), &supported_ops);

  auto result = module.walk([&](tf_device::ClusterOp cluster) {
    // Only if `allow_soft_placement` attribute is true should we mark ops
    // for outside compilation.
    auto soft_placement_attr =
        cluster.getAttrOfType<BoolAttr>(kAllowSoftPlacementAttr);
    if (!(soft_placement_attr && soft_placement_attr.getValue())) {
      return WalkResult::advance();
    }
    if (failed(
            MarkUncompilableOps(tf_dialect, &cluster.GetBody(), supported_ops)))
      return WalkResult::interrupt();

    return WalkResult::advance();
  });

  if (result.wasInterrupted()) return signalPassFailure();

  module.walk([&](tf_device::ClusterOp cluster) {
    // Only if `allow_soft_placement` attribute is true should we unmark ops
    // for outside compilation.
    auto soft_placement_attr =
        cluster.getAttrOfType<BoolAttr>(kAllowSoftPlacementAttr);
    if (!(soft_placement_attr && soft_placement_attr.getValue())) {
      return;
    }
    UnmarkChildren(&cluster.GetBody());
  });
}

}  // namespace

std::unique_ptr<OperationPass<ModuleOp>>
CreateMarkOpsForOutsideCompilationPass() {
  return std::make_unique<MarkOpsForOutsideCompilation>();
}

static PassRegistration<MarkOpsForOutsideCompilation> pass(
    "tf-mark-ops-for-outside-compilation",
    "Marks unsupported ops a device cluster for outside compilation.");

}  // namespace TFDevice
}  // namespace mlir
<commit_msg>Remove redundant `TensorListFromTensor` op from the list of supported ops.<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include <memory>
#include <string>
#include <utility>

#include "llvm/Support/FormatVariadic.h"
#include "mlir/IR/TypeUtilities.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Pass/PassRegistry.h"  // from @llvm-project
#include "mlir/Transforms/RegionUtils.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_device.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/lower_tf.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"
#include "tensorflow/compiler/mlir/xla/transforms/passes.h"
#include "tensorflow/core/lib/monitoring/gauge.h"

namespace mlir {
namespace TFDevice {

namespace {

constexpr char kXlaOutsideCompilationAttr[] = "_xla_outside_compilation";
constexpr char kAllowSoftPlacementAttr[] = "allow_soft_placement";

auto* auto_outside_compilation_gauge =
    tensorflow::monitoring::Gauge<bool, 0>::New(
        "/tensorflow/core/use_auto_outside_compilation",
        "Tracks if auto outside compilation is enabled");

// This pass marks unsupported ops in a device cluster with
// `_xla_outside_compilation` attribute so the operations will run on the host
// instead of the device.  Unsupported ops are ops that can not be code
// generated to run on the device for the cluster.
struct MarkOpsForOutsideCompilation
    : public PassWrapper<MarkOpsForOutsideCompilation,
                         OperationPass<ModuleOp>> {
  void runOnOperation() override;
};

// Adds any canonicalization patterns to list of supported `patterns`.
// TODO(b/161726307): Move or import the relevant patterns to LowerTF pass and
// remove this.
void AddCanonicalizationPatterns(MLIRContext* context,
                                 OwningRewritePatternList* patterns) {
  for (auto* op : context->getRegisteredOperations())
    op->getCanonicalizationPatterns(*patterns, context);
}

// TODO(b/159128666): Check the control flow legalization passes instead once
// added.
void AddSupportedControlFlowOps(MLIRContext* context,
                                llvm::DenseSet<OperationName>* supported_ops) {
  supported_ops->insert(
      OperationName(TF::IfRegionOp::getOperationName(), context));
  supported_ops->insert(
      OperationName(TF::WhileRegionOp::getOperationName(), context));
  supported_ops->insert(
      OperationName(TF::YieldOp::getOperationName(), context));
}

// These embedding ops are rewritten when running TPUCompileOp.
void AddRewrittenEmbeddingOps(MLIRContext* context,
                              llvm::DenseSet<OperationName>* supported_ops) {
  supported_ops->insert(OperationName(
      TF::RecvTPUEmbeddingActivationsOp::getOperationName(), context));
  supported_ops->insert(OperationName(
      TF::SendTPUEmbeddingGradientsOp::getOperationName(), context));
}

// Stack, TensorList and TensorArray ops are rewritten during the second phase
// of the bridge (compilation of TPUCompile op). They would not match any
// legalization/canonicalization pattern and have to be manually added to the
// list of supported ops.
void AddRewrittenCompositeOps(MLIRContext* context,
                              llvm::DenseSet<OperationName>* supported_ops) {
#define GET_OPERATION_NAME(op) OperationName(op::getOperationName(), context)
  llvm::SmallDenseSet<OperationName, 32> allowlist_ops = {
      // Stack ops.
      GET_OPERATION_NAME(TF::StackV2Op),
      GET_OPERATION_NAME(TF::StackPushV2Op),
      GET_OPERATION_NAME(TF::StackPopV2Op),
      // Tensor Array ops.
      GET_OPERATION_NAME(TF::TensorArrayV3Op),
      GET_OPERATION_NAME(TF::TensorArrayReadV3Op),
      GET_OPERATION_NAME(TF::TensorArrayWriteV3Op),
      GET_OPERATION_NAME(TF::TensorArrayConcatV3Op),
      GET_OPERATION_NAME(TF::TensorArraySplitV3Op),
      GET_OPERATION_NAME(TF::TensorArraySizeV3Op),
      GET_OPERATION_NAME(TF::TensorArrayGradV3Op),
      GET_OPERATION_NAME(TF::TensorArrayGatherV3Op),
      GET_OPERATION_NAME(TF::TensorArrayScatterV3Op),
      // Tensor List Ops.
      GET_OPERATION_NAME(TF::EmptyTensorListOp),
      GET_OPERATION_NAME(TF::TensorListReserveOp),
      GET_OPERATION_NAME(TF::TensorListFromTensorOp),
      GET_OPERATION_NAME(TF::TensorListPushBackOp),
      GET_OPERATION_NAME(TF::TensorListPopBackOp),
      GET_OPERATION_NAME(TF::TensorListGetItemOp),
      GET_OPERATION_NAME(TF::TensorListSetItemOp),
      GET_OPERATION_NAME(TF::TensorListLengthOp),
      GET_OPERATION_NAME(TF::TensorListElementShapeOp),
      GET_OPERATION_NAME(TF::TensorListGatherOp),
      GET_OPERATION_NAME(TF::TensorListScatterIntoExistingListOp),
  };
#undef GET_OPERATION_NAME

  supported_ops->insert(allowlist_ops.begin(), allowlist_ops.end());
}

bool IsStringType(Type type) {
  if (type.isa<TF::StringType>()) return true;

  auto sub_type = type.dyn_cast<TF::TensorFlowTypeWithSubtype>();
  if (!sub_type) return false;

  bool has_string = llvm::any_of(sub_type.GetSubtypes(), [](TensorType type) {
    return type.getElementType().isa<TF::StringType>();
  });
  return has_string;
}

bool HasStringOperand(Operation& op) {
  for (auto operand : op.getOperands()) {
    auto operand_type = getElementTypeOrSelf(operand);
    if (IsStringType(operand_type)) return true;
  }
  return false;
}

bool HasStringResult(Operation& op) {
  for (auto result : op.getResults()) {
    auto result_type = getElementTypeOrSelf(result);
    if (IsStringType(result_type)) return true;
  }
  return false;
}

bool MatchesPattern(Operation& op,
                    const llvm::DenseSet<OperationName>& supported_ops) {
  return (supported_ops.contains(op.getName()));
}

// Checks if the op is supported inside of a device cluster.  Ops not
// in `tf_dialect` are considered supported.
bool IsSupportedOp(Operation& op,
                   const llvm::DenseSet<OperationName>& supported_ops,
                   const Dialect* tf_dialect) {
  if (op.getDialect() != tf_dialect)
    return true;
  // Assert has a legalization that later removes it so we don't want to outside
  // compile it ever for performance reasons.
  if (llvm::isa<TF::AssertOp>(op)) return true;
  return !HasStringOperand(op) && !HasStringResult(op) &&
         (MatchesPattern(op, supported_ops) ||
          mhlo::IsOpAllowedTf2XlaFallback(&op));
}

// Checks all regions of `op` for captured string operands.
bool HasCapturedStringOperand(Operation* op) {
  bool string_operand = false;
  for (auto& region : op->getRegions()) {
    mlir::visitUsedValuesDefinedAbove(
        region, region, [&](mlir::OpOperand* operand) {
          if (getElementTypeOrSelf(operand->get()).isa<TF::StringType>())
            string_operand = true;
        });
    if (string_operand) return string_operand;
  }
  return string_operand;
}

// Marks uncompilable ops that are in `tf_dialect` for outside compilation.
LogicalResult MarkUncompilableOps(
    const Dialect* tf_dialect, Block* block,
    llvm::DenseSet<OperationName>& supported_ops) {
  // Automatically marked ops for outside compilation have
  // `_xla_outside_compilation` attribute value of "auto" plus
  // an increasing counter.  Manually marked ops for outside compilation only
  // have an increasing counteri for the attribute value.  Therefore there is no
  // collision in
  // `_xla_outside_compilation` attribute between automatically and manually
  // marking ops.
  int outside_compiled_cluster_counter = 0;
  block->walk([&](Operation* op) {
    if (!IsSupportedOp(*op, supported_ops, tf_dialect)) {
      op->setAttr(
          kXlaOutsideCompilationAttr,
          StringAttr::get(
              llvm::formatv("auto{0}", outside_compiled_cluster_counter).str(),
              op->getContext()));
      outside_compiled_cluster_counter++;
    }
  });
  if (outside_compiled_cluster_counter > 0) {
    auto_outside_compilation_gauge->GetCell()->Set(true);
  }
  return success();
}

// Unmarks outside compilation for any op that has parents already
// marked for outside compilation since the child will be extracted
// anyways.
void UnmarkChildren(Block* block) {
  block->walk([&](Operation* op) {
    if (!op->getAttrOfType<StringAttr>(kXlaOutsideCompilationAttr)) return;
    Operation* iter_op = op;
    bool remove_attr = false;
    while (auto* parent_op = iter_op->getParentOp()) {
      if (parent_op->getAttrOfType<StringAttr>(kXlaOutsideCompilationAttr)) {
        remove_attr = true;
        break;
      }
      iter_op = parent_op;
    }
    if (remove_attr) op->removeAttr(kXlaOutsideCompilationAttr);
  });
}

void MarkOpsForOutsideCompilation::runOnOperation() {
  auto module = getOperation();
  const Dialect* tf_dialect = getContext().getLoadedDialect("tf");
  if (!tf_dialect) {
    getOperation().emitError() << "'tf' dialect is not registered";
    return signalPassFailure();
  }
  OwningRewritePatternList patterns;
  mhlo::PopulateLegalizeTfPatterns(module.getContext(), &patterns);
  TF::PopulateLoweringTFPatterns(module.getContext(), &patterns);
  AddCanonicalizationPatterns(module.getContext(), &patterns);

  // `supported_ops` contains the name of all of the ops that can potentially be
  // lowered into HLO on the device. This doesn't always mean that the op can
  // be lowered in the future passes but if the op is not in this set, it can't
  // be lowered in a subsequent pass.
  llvm::DenseSet<OperationName> supported_ops;
  for (auto& pattern : patterns) {
    Optional<OperationName> root_kind = pattern->getRootKind();
    if (root_kind.hasValue()) supported_ops.insert(root_kind.getValue());
  }
  AddSupportedControlFlowOps(module.getContext(), &supported_ops);
  AddRewrittenEmbeddingOps(module.getContext(), &supported_ops);
  AddRewrittenCompositeOps(module.getContext(), &supported_ops);

  auto result = module.walk([&](tf_device::ClusterOp cluster) {
    // Only if `allow_soft_placement` attribute is true should we mark ops
    // for outside compilation.
    auto soft_placement_attr =
        cluster.getAttrOfType<BoolAttr>(kAllowSoftPlacementAttr);
    if (!(soft_placement_attr && soft_placement_attr.getValue())) {
      return WalkResult::advance();
    }
    if (failed(
            MarkUncompilableOps(tf_dialect, &cluster.GetBody(), supported_ops)))
      return WalkResult::interrupt();

    return WalkResult::advance();
  });

  if (result.wasInterrupted()) return signalPassFailure();

  module.walk([&](tf_device::ClusterOp cluster) {
    // Only if `allow_soft_placement` attribute is true should we unmark ops
    // for outside compilation.
    auto soft_placement_attr =
        cluster.getAttrOfType<BoolAttr>(kAllowSoftPlacementAttr);
    if (!(soft_placement_attr && soft_placement_attr.getValue())) {
      return;
    }
    UnmarkChildren(&cluster.GetBody());
  });
}

}  // namespace

std::unique_ptr<OperationPass<ModuleOp>>
CreateMarkOpsForOutsideCompilationPass() {
  return std::make_unique<MarkOpsForOutsideCompilation>();
}

static PassRegistration<MarkOpsForOutsideCompilation> pass(
    "tf-mark-ops-for-outside-compilation",
    "Marks unsupported ops a device cluster for outside compilation.");

}  // namespace TFDevice
}  // namespace mlir
<|endoftext|>


<commit_before>#include "popupmenu.h"
#include "popupwidgetitem.h"

#include <QDebug>
#include <QScrollBar>

namespace NeovimQt {

PopupMenu::PopupMenu(ShellWidget* parent) :
	QListView(parent),
	m_parentShellWidget{ parent }
{
	setFocusPolicy(Qt::NoFocus);
	setAttribute(Qt::WA_TransparentForMouseEvents);
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setViewMode(QListView::ListMode);
}

QSize PopupMenu::sizeHint() const {
	if (!model()) {
		return {};
	}

	int height = 0;
	for (int i=0; i<model()->rowCount(); i++) {
		height += sizeHintForRow(i);
	}
	return QSize(sizeHintForColumn(0) + 2*frameWidth(),
			height + 2*frameWidth());
}

void PopupMenu::setAnchor(int64_t row, int64_t col)
{
	m_anchorRow = row;
	m_anchorCol = col;
}

void PopupMenu::setSelectedIndex(int64_t index)
{
	if (!model()) {
		return;
	}

	QModelIndex idx = model()->index(index, 0);
	setCurrentIndex(idx);
	scrollTo(idx);
}

void PopupMenu::updateGeometry()
{
	setGeometry(m_anchorRow, m_anchorCol);
	QListView::updateGeometry();
}

void PopupMenu::setGeometry(int64_t row, int64_t col)
{
	const QSize sizeHintContent = sizeHint();

	if (!m_parentShellWidget) {
		const int width = sizeHintContent.width();
		const int height = sizeHintContent.height();

		qDebug() << "Fallback: PUM anchored to 0,0 without parent shell_widget!";
		return QListView::setGeometry(0, 0, width, height);
	}

	const int cell_width = m_parentShellWidget->cellSize().width();
	const int min_width = 20 * cell_width;
	const int total_width = m_parentShellWidget->columns() * cell_width;

	// Compute default width properties (anchor_x, width)
	int width = sizeHintContent.width();
	int anchor_x = col * cell_width;

	// PUM must fit within available space to the right of anchor_x
	if (anchor_x + width > total_width)
	{
		width = total_width - anchor_x;

		// PUM should never go below minimum width
		if (width < min_width)
		{
			anchor_x = 0;
			width = qMin(total_width, sizeHintContent.width());
		}
	}

	const int cell_height = m_parentShellWidget->cellSize().height();
	const int min_height = 15 * cell_height;
	const int space_above_row = row * cell_height + 1;
	const int space_below_row =
		(m_parentShellWidget->rows() - row - 2) * cell_height + 1;

	// Compute default height properties (anchor_y, height)
	int height = sizeHintContent.height();
	int anchor_y = (row + 1) * cell_height;

	if (height < space_below_row) {
		// PUM defaults work fine. Keep this case.
	}
	else if (space_below_row >= min_height) {
		// Truncate PUM to space available below anchor.
		height = space_below_row;
	}
	else if (height < space_above_row) {
		// Space available for PUM above anchor.
		anchor_y = (row - 1) * cell_height - height;
	}
	else if (space_above_row > space_below_row) {
		// Not enough space for min_height, more space above.
		anchor_y = 0;
		height = space_above_row;
	}
	else {
		// Not enough space for min_height, more space below.
		height = space_below_row;
		anchor_y = (row + 1) * cell_height;
	}

	return QListView::setGeometry(anchor_x, anchor_y, width, height);
}

} // Namespace
<commit_msg>Issue 693: GuiPopupmenu ScrollBar Truncation<commit_after>#include "popupmenu.h"
#include "popupwidgetitem.h"

#include <QDebug>
#include <QScrollBar>

namespace NeovimQt {

PopupMenu::PopupMenu(ShellWidget* parent) :
	QListView(parent),
	m_parentShellWidget{ parent }
{
	setFocusPolicy(Qt::NoFocus);
	setAttribute(Qt::WA_TransparentForMouseEvents);
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setViewMode(QListView::ListMode);
}

QSize PopupMenu::sizeHint() const {
	if (!model()) {
		return {};
	}

	int height = 0;
	for (int i=0; i<model()->rowCount(); i++) {
		height += sizeHintForRow(i);
	}
	return QSize(sizeHintForColumn(0) + 2*frameWidth(),
			height + 2*frameWidth());
}

void PopupMenu::setAnchor(int64_t row, int64_t col)
{
	m_anchorRow = row;
	m_anchorCol = col;
}

void PopupMenu::setSelectedIndex(int64_t index)
{
	if (!model()) {
		return;
	}

	QModelIndex idx = model()->index(index, 0);
	setCurrentIndex(idx);
	scrollTo(idx);
}

void PopupMenu::updateGeometry()
{
	setGeometry(m_anchorRow, m_anchorCol);
	QListView::updateGeometry();
}

void PopupMenu::setGeometry(int64_t row, int64_t col)
{
	const QSize sizeHintContent = sizeHint();

	if (!m_parentShellWidget) {
		const int width = sizeHintContent.width();
		const int height = sizeHintContent.height();

		qDebug() << "Fallback: PUM anchored to 0,0 without parent shell_widget!";
		return QListView::setGeometry(0, 0, width, height);
	}

	const int cell_width = m_parentShellWidget->cellSize().width();
	const int min_width = 20 * cell_width;
	const int total_width = m_parentShellWidget->columns() * cell_width;

	// Compute default width properties (anchor_x, width)
	int width = sizeHintContent.width();
	int anchor_x = col * cell_width;

	// Scrollbar visibility depends on content, increase width when necessary.
	const QScrollBar* vScrollBar{ verticalScrollBar() };
	if (vScrollBar && vScrollBar->isVisible())
	{
		width += vScrollBar->size().width();
	}

	// PUM must fit within available space to the right of anchor_x
	if (anchor_x + width > total_width)
	{
		width = total_width - anchor_x;

		// PUM should never go below minimum width
		if (width < min_width)
		{
			anchor_x = 0;
			width = qMin(total_width, sizeHintContent.width());
		}
	}

	const int cell_height = m_parentShellWidget->cellSize().height();
	const int min_height = 15 * cell_height;
	const int space_above_row = row * cell_height + 1;
	const int space_below_row =
		(m_parentShellWidget->rows() - row - 2) * cell_height + 1;

	// Compute default height properties (anchor_y, height)
	int height = sizeHintContent.height();
	int anchor_y = (row + 1) * cell_height;

	if (height < space_below_row) {
		// PUM defaults work fine. Keep this case.
	}
	else if (space_below_row >= min_height) {
		// Truncate PUM to space available below anchor.
		height = space_below_row;
	}
	else if (height < space_above_row) {
		// Space available for PUM above anchor.
		anchor_y = (row - 1) * cell_height - height;
	}
	else if (space_above_row > space_below_row) {
		// Not enough space for min_height, more space above.
		anchor_y = 0;
		height = space_above_row;
	}
	else {
		// Not enough space for min_height, more space below.
		height = space_below_row;
		anchor_y = (row + 1) * cell_height;
	}

	return QListView::setGeometry(anchor_x, anchor_y, width, height);
}

} // Namespace
<|endoftext|>


<commit_before>#include <cstdlib>
#include <sstream>

#include "headers.hpp"
#include "helloByeProto.hpp"
#include "IPv4_5TupleL2Ident.hpp"
#include "samplePacket.hpp"

using namespace Headers;
using namespace std;

/*
 * ===================================
 * HelloByeServerHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeServerHello<Identifier, Packet>::HelloByeServerHello() {
	this->serverCookie = rand();
};

template <class Identifier, class Packet>
void HelloByeServerHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT HELLO:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) == 0) {
		cout << "HelloByeServerHello::fun() clientStr didn't match" << endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr)];
	this->clientCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "SERVER HELLO:" << this->serverCookie << endl;
	string serverHelloStr = sstream.str();
	memcpy(udp->getPayload(), serverHelloStr.c_str(), serverHelloStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	uint32_t tmp = ipv4->ip_dst.s_addr;
	ipv4->ip_dst.s_addr = ipv4->ip_src.s_addr;
	ipv4->ip_src.s_addr = tmp;
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	uint16_t tmp16 = udp->dest;
	udp->dest = udp->source;
	udp->source = tmp16;

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeServerBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeServerBye<Identifier, Packet>::HelloByeServerBye(
	const HelloByeServerHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloByeServerBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT BYE:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) == 0) {
		cout << "HelloByeServerBye::fun() clientStr didn't match" << endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr)];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if(recvCookie != this->serverCookie){
		cout << "HelloByeServerBye::fun() Client sent over wrong cookie" << endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "SERVER BYE:" << this->clientCookie << endl;
	string serverByeStr = sstream.str();
	memcpy(udp->getPayload(), serverByeStr.c_str(), serverByeStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	uint32_t tmp = ipv4->ip_dst.s_addr;
	ipv4->ip_dst.s_addr = ipv4->ip_src.s_addr;
	ipv4->ip_src.s_addr = tmp;
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	uint16_t tmp16 = udp->dest;
	udp->dest = udp->source;
	udp->source = tmp16;

	// We are done after this -> transition to Terminate
	state.transition(HelloByeServer::Terminate);

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeClientHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeClientHello<Identifier, Packet>::HelloByeClientHello(uint32_t dstIp, uint16_t srcPort)
	: dstIp(dstIp), srcPort(srcPort) {
	this->clientCookie = rand();
};

template <class Identifier, class Packet>
void HelloByeClientHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// pkt is empty -> get one
	pkt = funIface.getPkt();
	memset(pkt->getData(), 0, pkt->getDataLen());

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	HelloByeClientConfig *config = HelloByeClientConfig::getInstance();

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "CLIENT HELLO:" << this->clientCookie << endl;
	string clientHelloStr = sstream.str();
	memcpy(udp->getPayload(), clientHelloStr.c_str(), clientHelloStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	ipv4->ip_dst.s_addr = dstIp;
	ipv4->ip_src.s_addr = config->getSrcIP();
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	udp->dest = config->getDstPort();
	udp->source = srcPort;

	state.transition(HelloByeClient::Bye);

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeClientBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeClientBye<Identifier, Packet>::HelloByeClientBye(
	const HelloByeClientHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie) {}

template <class Identifier, class Packet>
void HelloByeClientBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER HELLO:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) == 0) {
		cout << "HelloByeClientBye::fun() serverStr didn't match" << endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get server cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr)];
	this->serverCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "CLIENT BYE:" << this->serverCookie << endl;
	string clientByeStr = sstream.str();
	memcpy(udp->getPayload(), clientByeStr.c_str(), clientByeStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	uint32_t tmp = ipv4->ip_dst.s_addr;
	ipv4->ip_dst.s_addr = ipv4->ip_src.s_addr;
	ipv4->ip_src.s_addr = tmp;
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	uint16_t tmp16 = udp->dest;
	udp->dest = udp->source;
	udp->source = tmp16;

	// We need to wait for the server reply
	state.transition(HelloByeClient::RecvBye);

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeClientRecvBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeClientRecvBye<Identifier, Packet>::HelloByeClientRecvBye(
	const HelloByeClientBye<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloByeClientRecvBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER BYE:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) == 0) {
		cout << "HelloByeClientRecvBye::fun() serverStr didn't match" << endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr)];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if(recvCookie != this->clientCookie){
		cout << "HelloByeClientRecvBye::fun() Server sent over wrong cookie" << endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// We are done after this -> transition to Terminate
	state.transition(HelloByeClient::Terminate);

	funIface.addPktToFree(pkt);
};

/*
 * ===================================
 * Prepare template instances
 * ===================================
 *
 */

template class HelloByeServerHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeServerBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeClientHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeClientBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeClientRecvBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;

/*
 * ===================================
 * Define Client config singleton
 * ===================================
 *
 */

HelloByeClientConfig* HelloByeClientConfig::instance = nullptr;

<commit_msg>bugfix + partly adapt to new header<commit_after>#include <cstdlib>
#include <sstream>

#include "headers.hpp"
#include "helloByeProto.hpp"
#include "IPv4_5TupleL2Ident.hpp"
#include "samplePacket.hpp"

using namespace Headers;
using namespace std;

/*
 * ===================================
 * HelloByeServerHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeServerHello<Identifier, Packet>::HelloByeServerHello() {
	this->serverCookie = rand();
};

template <class Identifier, class Packet>
void HelloByeServerHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT HELLO:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) != 0) {
		cout << "HelloByeServerHello::fun() clientStr didn't match" << endl;
		state.transition(HelloByeServer::Terminate);
		funIface.addPktToFree(pkt);
		return;
	}

	// Get client cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr)];
	this->clientCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "SERVER HELLO:" << this->serverCookie << endl;
	string serverHelloStr = sstream.str();
	memcpy(udp->getPayload(), serverHelloStr.c_str(), serverHelloStr.length());

	// Set the IP header stuff
	// Leave the payload length alone for now...

	ipv4->ttl = 64;
	uint32_t tmp = ipv4->dstIP;
	ipv4->dstIP = ipv4->srcIP;
	ipv4->srcIP = tmp;
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best

	udp->checksum = 0;
	uint16_t tmp16 = udp->dstPort;
	udp->dstPort = udp->srcPort;
	udp->srcPort = tmp16;

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeServerBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeServerBye<Identifier, Packet>::HelloByeServerBye(
	const HelloByeServerHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloByeServerBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char clientStr[] = "CLIENT BYE:";
	if (memcmp(udp->getPayload(), clientStr, sizeof(clientStr) - 1) != 0) {
		cout << "HelloByeServerBye::fun() clientStr didn't match" << endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(clientStr)];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if(recvCookie != this->serverCookie){
		cout << "HelloByeServerBye::fun() Client sent over wrong cookie" << endl;
		state.transition(HelloByeServer::Terminate);
		return;
	}

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "SERVER BYE:" << this->clientCookie << endl;
	string serverByeStr = sstream.str();
	memcpy(udp->getPayload(), serverByeStr.c_str(), serverByeStr.length());

	/*
	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	uint32_t tmp = ipv4->ip_dst.s_addr;
	ipv4->ip_dst.s_addr = ipv4->ip_src.s_addr;
	ipv4->ip_src.s_addr = tmp;
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	uint16_t tmp16 = udp->dest;
	udp->dest = udp->source;
	udp->source = tmp16;
*/
	// We are done after this -> transition to Terminate
	state.transition(HelloByeServer::Terminate);

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeClientHello
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeClientHello<Identifier, Packet>::HelloByeClientHello(uint32_t dstIp, uint16_t srcPort)
	: dstIp(dstIp), srcPort(srcPort) {
	this->clientCookie = rand();
};

template <class Identifier, class Packet>
void HelloByeClientHello<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// pkt is empty -> get one
	pkt = funIface.getPkt();
	memset(pkt->getData(), 0, pkt->getDataLen());

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	HelloByeClientConfig *config = HelloByeClientConfig::getInstance();

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "CLIENT HELLO:" << this->clientCookie << endl;
	string clientHelloStr = sstream.str();
	memcpy(udp->getPayload(), clientHelloStr.c_str(), clientHelloStr.length());

	/*
	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	ipv4->ip_dst.s_addr = dstIp;
	ipv4->ip_src.s_addr = config->getSrcIP();
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	udp->dest = config->getDstPort();
	udp->source = srcPort;
*/
	state.transition(HelloByeClient::Bye);

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeClientBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeClientBye<Identifier, Packet>::HelloByeClientBye(
	const HelloByeClientHello<Identifier, Packet> *in)
	: clientCookie(in->clientCookie) {}

template <class Identifier, class Packet>
void HelloByeClientBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER HELLO:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) != 0) {
		cout << "HelloByeClientBye::fun() serverStr didn't match" << endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get server cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr)];
	this->serverCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	// Prepare new packet
	// Set payload string
	stringstream sstream;
	sstream << "CLIENT BYE:" << this->serverCookie << endl;
	string clientByeStr = sstream.str();
	memcpy(udp->getPayload(), clientByeStr.c_str(), clientByeStr.length());

	/*
	// Set the IP header stuff
	// Leave the payload length alone for now...
	ipv4->ip_ttl = 64;
	uint32_t tmp = ipv4->ip_dst.s_addr;
	ipv4->ip_dst.s_addr = ipv4->ip_src.s_addr;
	ipv4->ip_src.s_addr = tmp;
	ipv4->calcChecksum();

	// Set UDP checksum to 0 and hope for the best
	udp->check = 0;
	uint16_t tmp16 = udp->dest;
	udp->dest = udp->source;
	udp->source = tmp16;
*/
	// We need to wait for the server reply
	state.transition(HelloByeClient::RecvBye);

	funIface.addPktToSend(pkt);
};

/*
 * ===================================
 * HelloByeClientRecvBye
 * ===================================
 *
 */

template <class Identifier, class Packet>
HelloByeClientRecvBye<Identifier, Packet>::HelloByeClientRecvBye(
	const HelloByeClientBye<Identifier, Packet> *in)
	: clientCookie(in->clientCookie), serverCookie(in->serverCookie) {}

template <class Identifier, class Packet>
void HelloByeClientRecvBye<Identifier, Packet>::fun(
	typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {

	// Get info from packet
	Ethernet *ether = reinterpret_cast<Ethernet *>(pkt->getData());
	IPv4 *ipv4 = reinterpret_cast<IPv4 *>(ether->getPayload());
	Udp *udp = reinterpret_cast<Udp *>(ipv4->getPayload());

	char serverStr[] = "SERVER BYE:";
	if (memcmp(udp->getPayload(), serverStr, sizeof(serverStr) - 1) != 0) {
		cout << "HelloByeClientRecvBye::fun() serverStr didn't match" << endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// Get client cookie
	uint8_t cookieChar = reinterpret_cast<uint8_t *>(udp->getPayload())[sizeof(serverStr)];
	int recvCookie = static_cast<int>(cookieChar) - 48; // ASCII Conversion

	if(recvCookie != this->clientCookie){
		cout << "HelloByeClientRecvBye::fun() Server sent over wrong cookie" << endl;
		state.transition(HelloByeClient::Terminate);
		return;
	}

	// We are done after this -> transition to Terminate
	state.transition(HelloByeClient::Terminate);

	funIface.addPktToFree(pkt);
};

/*
 * ===================================
 * Prepare template instances
 * ===================================
 *
 */

template class HelloByeServerHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeServerBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeClientHello<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeClientBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;
template class HelloByeClientRecvBye<IPv4_5TupleL2Ident<SamplePacket>, SamplePacket>;

/*
 * ===================================
 * Define Client config singleton
 * ===================================
 *
 */

HelloByeClientConfig* HelloByeClientConfig::instance = nullptr;

<|endoftext|>