<commit_before>#include <iostream>

#include "wicked.h"
#include "test.h"

using namespace std;

test_return_t test_Faa_Tca() {
  WDiagTheorem wdt;
  auto Faa = make_operator("f", {"a->a"});
  auto Tca = make_operator("t", {"c->a"});

  // [Faa,Tca]
  auto sum = wdt.contract_sum(1, commutator(Faa, Tca), 0, 2);

  auto sum_test =
      string_to_sum(
          "eta1^{a2}_{a1} f^{a1}_{a0} t^{c0}_{a2} { a+(a0) a-(c0) }") +
      string_to_sum(
          "f^{a1}_{a0} gamma1^{a2}_{a1} t^{c0}_{a2} { a+(a0) a-(c0) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Faa,Tca]"});
}

test_return_t test_Fvv_Tcv() {
  WDiagTheorem wdt;
  //  wdt.set_print(WDiagPrint::Basic);
  auto Fvv = make_operator("f", {"v->v"});
  auto Tcv = make_operator("t", {"c->v"});

  // [Fvv,Tcv]
  auto sum = wdt.contract_sum(1, commutator(Fvv, Tcv), 0, 2);

  auto sum_test = string_to_sum("f^{v1}_{v0} t^{c0}_{v1} { a+(v0) a-(c0) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Fvv,Tcv]"});
}

test_return_t test_Faa_Tav() {
  WDiagTheorem wdt;
  auto Faa = make_operator("f", {"a->a"});
  auto Tav = make_operator("t", {"a->v"});

  // [Faa,Tav]
  auto sum = wdt.contract_sum(1, commutator(Faa, Tav), 0, 2);

  cout << "\n\n" << sum.latex() << endl;

  auto sum_test =
      string_to_sum(
          "eta1^{a2}_{a1} f^{a1}_{a0} t^{c0}_{a2} { a+(a0) a-(c0) }") +
      string_to_sum(
          "f^{a1}_{a0} gamma1^{a2}_{a1} t^{c0}_{a2} { a+(a0) a-(c0) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Faa,Tav]"});
}

int main(int argc, const char *argv[]) {

  // Define the orbital space
  osi = std::make_shared<OrbitalSpaceInfo>();
  osi->add_space("c", RDMType::Occupied, {"i", "j", "k", "l", "m", "n"});
  osi->add_space("a", RDMType::General, {"u", "v", "w", "x", "y", "z"});
  osi->add_space("v", RDMType::Unoccupied, {"a", "b", "c", "d", "e", "f"});

  // Assemble the tests
  auto test_functions = {test_Faa_Tca, test_Fvv_Tcv, test_Faa_Tav};

  // Run the tests
  bool success = wicked_test(test_functions);

  return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
<commit_msg>Adds more tests to MR-DSRG.<commit_after>#include <iostream>

#include "wicked.h"
#include "test.h"

using namespace std;

test_return_t test_Fac_Tca() {
  WDiagTheorem wdt;
  auto Fac = make_operator("f", {"a->c"});
  auto Tca = make_operator("t", {"c->a"});

  // [Fac,Tca]
  auto sum = wdt.contract_sum(1, commutator(Fac, Tca), 0, 2);

  auto sum_test =
      string_to_sum("eta1^{a1}_{a0} f^{a0}_{c0} t^{c0}_{a1}") +
      string_to_sum(
          "eta1^{a1}_{a0} f^{a0}_{c0} t^{c1}_{a1} { a+(c0) a-(c1) }") +
      string_to_sum("-f^{a0}_{c0} t^{c0}_{a1} { a+(a1) a-(a0) }") +
      string_to_sum(
          "f^{a0}_{c0} gamma1^{a1}_{a0} t^{c1}_{a1} { a+(c0) a-(c1) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Fac,Tca]"});
}

test_return_t test_Faa_Tca() {
  WDiagTheorem wdt;
  auto Faa = make_operator("f", {"a->a"});
  auto Tca = make_operator("t", {"c->a"});

  // [Faa,Tca]
  auto sum = wdt.contract_sum(1, commutator(Faa, Tca), 0, 2);

  auto sum_test =
      string_to_sum(
          "eta1^{a2}_{a1} f^{a1}_{a0} t^{c0}_{a2} { a+(a0) a-(c0) }") +
      string_to_sum(
          "f^{a1}_{a0} gamma1^{a2}_{a1} t^{c0}_{a2} { a+(a0) a-(c0) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Faa,Tca]"});
}

test_return_t test_Fvv_Tcv() {
  WDiagTheorem wdt;
  //  wdt.set_print(WDiagPrint::Basic);
  auto Fvv = make_operator("f", {"v->v"});
  auto Tcv = make_operator("t", {"c->v"});

  // [Fvv,Tcv]
  auto sum = wdt.contract_sum(1, commutator(Fvv, Tcv), 0, 2);

  auto sum_test = string_to_sum("f^{v1}_{v0} t^{c0}_{v1} { a+(v0) a-(c0) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Fvv,Tcv]"});
}

test_return_t test_Faa_Tav() {
  WDiagTheorem wdt;
  auto Faa = make_operator("f", {"a->a"});
  auto Tav = make_operator("t", {"a->v"});

  // [Faa,Tav]
  auto sum = wdt.contract_sum(1, commutator(Faa, Tav), 0, 2);

  auto sum_test =
      string_to_sum(
          "-eta1^{a2}_{a1} f^{a0}_{a2} t^{a1}_{v0} { a+(v0) a-(a0) }") +
      string_to_sum(
          "-f^{a0}_{a1} gamma1^{a1}_{a2} t^{a2}_{v0} { a+(v0) a-(a0) }");

  bool pass = (sum == sum_test);
  return make_return_t(TestPass, pass, {"[Faa,Tav]"});
}

int main(int argc, const char *argv[]) {

  // Define the orbital space
  osi = std::make_shared<OrbitalSpaceInfo>();
  osi->add_space("c", RDMType::Occupied, {"i", "j", "k", "l", "m", "n"});
  osi->add_space("a", RDMType::General, {"u", "v", "w", "x", "y", "z"});
  osi->add_space("v", RDMType::Unoccupied, {"a", "b", "c", "d", "e", "f"});

  // Assemble the tests
  auto test_functions = {test_Fac_Tca, test_Faa_Tca, test_Fvv_Tcv,
                         test_Faa_Tav};

  // Run the tests
  bool success = wicked_test(test_functions);

  return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014-2016 Alexander Saprykin <xelfium@gmail.com>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, see <http://www.gnu.org/licenses/>.
 */

#ifndef PLIBSYS_TESTS_STATIC
#  define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MODULE pmacros_test

#include "plibsys.h"

#include <stdlib.h>
#include <time.h>

#ifdef PLIBSYS_TESTS_STATIC
#  include <boost/test/included/unit_test.hpp>
#else
#  include <boost/test/unit_test.hpp>
#endif

static P_GNUC_WARN_UNUSED_RESULT pint unused_result_test_func ()
{
	return 0;
}

BOOST_AUTO_TEST_SUITE (BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE (pmacros_general_test)
{
	p_libsys_init ();

	/* Test OS detection macros */
#if !defined (P_OS_DARWIN) && !defined (P_OS_MAC9)     && !defined (P_OS_BSD4)      && \
    !defined (P_OS_AIX)    && !defined (P_OS_HPUX)     && !defined (P_OS_SOLARIS)   && \
    !defined (P_OS_QNX)    && !defined (P_OS_QNX6)     && !defined (P_OS_UNIX)      && \
    !defined (P_OS_LINUX)  && !defined (P_OS_WIN)      && !defined (P_OS_CYGWIN)    && \
    !defined (P_OS_SCO)    && !defined (P_OS_UNIXWARE) && !defined (P_OS_VMS)       && \
    !defined (P_OS_IRIX)   && !defined (P_OS_MSYS)     && !defined (P_OS_DRAGONFLY) && \
    !defined (P_OS_HAIKU)  && !defined (P_OS_TRU64)
	BOOST_CHECK (false);
#endif

	/* Test for Mac OS */
#if defined (P_OS_MAC9) && defined (P_OS_UNIX)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC9) && defined (P_OS_MAC)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC) && !defined (P_OS_MAC32) && !defined (P_OS_MAC64)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC) && (!defined (P_OS_DARWIN) || !defined (P_OS_BSD4))
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC32) && !defined (P_OS_DARWIN32)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC64) && !defined (P_OS_DARWIN64)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC32) && defined (P_OS_MAC64)
	BOOST_CHECK (false);
#endif

	/* Test for Windows */
#if defined (P_OS_WIN64) && !defined (P_OS_WIN)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_WIN) && defined (P_OS_UNIX)
	BOOST_CHECK (false);
#endif

	/* Test for FreeBSD */
#if defined (P_OS_FREEBSD) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for DragonFlyBSD */
#if defined (P_OS_DRAGONFLY) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for NetBSD */
#if defined (P_OS_NETBSD) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for OpenBSD */
#if defined (P_OS_OPENBSD) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for compiler detection macros */
#if !defined (P_CC_MSVC)    && !defined (P_CC_GNU)   && !defined (P_CC_MINGW)  && \
    !defined (P_CC_INTEL)   && !defined (P_CC_CLANG) && !defined (P_CC_SUN)    && \
    !defined (P_CC_XLC)     && !defined (P_CC_HP)    && !defined (P_CC_WATCOM) && \
    !defined (P_CC_BORLAND) && !defined (P_CC_MIPS)  && !defined (P_CC_USLC)   && \
    !defined (P_CC_DEC)
	BOOST_CHECK (false);
#endif

	/* Test other macros */
	pint unused = 8;
	P_UNUSED (unused);

	pint result = unused_result_test_func ();

	P_WARNING ("Test warning output");
	P_ERROR ("Test error output");
	P_DEBUG ("Test debug output");

	srand ((unsigned int) time (NULL));

	pint rand_number = rand ();

	if (P_LIKELY (rand_number > 0))
		P_DEBUG ("Likely condition triggered");

	if (P_UNLIKELY (rand_number == 0))
		P_DEBUG ("Unlikely condition triggered");

	/* Test version macros */
	BOOST_CHECK (PLIBSYS_VERSION_MAJOR >= 0);
	BOOST_CHECK (PLIBSYS_VERSION_MINOR >= 0);
	BOOST_CHECK (PLIBSYS_VERSION_PATCH >= 0);
	BOOST_CHECK (PLIBSYS_VERSION >= 0);

#if !defined (PLIBSYS_VERSION_STR)
	BOOST_CHECK (false);
#endif

	BOOST_CHECK (PLIBSYS_VERSION >= PLIBSYS_VERSION_CHECK (0, 0, 1));

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>tests: Add checks for Syllable predefined macro<commit_after>/*
 * Copyright (C) 2014-2016 Alexander Saprykin <xelfium@gmail.com>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, see <http://www.gnu.org/licenses/>.
 */

#ifndef PLIBSYS_TESTS_STATIC
#  define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MODULE pmacros_test

#include "plibsys.h"

#include <stdlib.h>
#include <time.h>

#ifdef PLIBSYS_TESTS_STATIC
#  include <boost/test/included/unit_test.hpp>
#else
#  include <boost/test/unit_test.hpp>
#endif

static P_GNUC_WARN_UNUSED_RESULT pint unused_result_test_func ()
{
	return 0;
}

BOOST_AUTO_TEST_SUITE (BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE (pmacros_general_test)
{
	p_libsys_init ();

	/* Test OS detection macros */
#if !defined (P_OS_DARWIN) && !defined (P_OS_MAC9)     && !defined (P_OS_BSD4)      && \
    !defined (P_OS_AIX)    && !defined (P_OS_HPUX)     && !defined (P_OS_SOLARIS)   && \
    !defined (P_OS_QNX)    && !defined (P_OS_QNX6)     && !defined (P_OS_UNIX)      && \
    !defined (P_OS_LINUX)  && !defined (P_OS_WIN)      && !defined (P_OS_CYGWIN)    && \
    !defined (P_OS_SCO)    && !defined (P_OS_UNIXWARE) && !defined (P_OS_VMS)       && \
    !defined (P_OS_IRIX)   && !defined (P_OS_MSYS)     && !defined (P_OS_DRAGONFLY) && \
    !defined (P_OS_HAIKU)  && !defined (P_OS_TRU64)    && !defined (P_OS_SYLLABLE)
	BOOST_CHECK (false);
#endif

	/* Test for Mac OS */
#if defined (P_OS_MAC9) && defined (P_OS_UNIX)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC9) && defined (P_OS_MAC)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC) && !defined (P_OS_MAC32) && !defined (P_OS_MAC64)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC) && (!defined (P_OS_DARWIN) || !defined (P_OS_BSD4))
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC32) && !defined (P_OS_DARWIN32)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC64) && !defined (P_OS_DARWIN64)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_MAC32) && defined (P_OS_MAC64)
	BOOST_CHECK (false);
#endif

	/* Test for Windows */
#if defined (P_OS_WIN64) && !defined (P_OS_WIN)
	BOOST_CHECK (false);
#endif

#if defined (P_OS_WIN) && defined (P_OS_UNIX)
	BOOST_CHECK (false);
#endif

	/* Test for FreeBSD */
#if defined (P_OS_FREEBSD) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for DragonFlyBSD */
#if defined (P_OS_DRAGONFLY) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for NetBSD */
#if defined (P_OS_NETBSD) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for OpenBSD */
#if defined (P_OS_OPENBSD) && !defined (P_OS_BSD4)
	BOOST_CHECK (false);
#endif

	/* Test for compiler detection macros */
#if !defined (P_CC_MSVC)    && !defined (P_CC_GNU)   && !defined (P_CC_MINGW)  && \
    !defined (P_CC_INTEL)   && !defined (P_CC_CLANG) && !defined (P_CC_SUN)    && \
    !defined (P_CC_XLC)     && !defined (P_CC_HP)    && !defined (P_CC_WATCOM) && \
    !defined (P_CC_BORLAND) && !defined (P_CC_MIPS)  && !defined (P_CC_USLC)   && \
    !defined (P_CC_DEC)
	BOOST_CHECK (false);
#endif

	/* Test other macros */
	pint unused = 8;
	P_UNUSED (unused);

	pint result = unused_result_test_func ();

	P_WARNING ("Test warning output");
	P_ERROR ("Test error output");
	P_DEBUG ("Test debug output");

	srand ((unsigned int) time (NULL));

	pint rand_number = rand ();

	if (P_LIKELY (rand_number > 0))
		P_DEBUG ("Likely condition triggered");

	if (P_UNLIKELY (rand_number == 0))
		P_DEBUG ("Unlikely condition triggered");

	/* Test version macros */
	BOOST_CHECK (PLIBSYS_VERSION_MAJOR >= 0);
	BOOST_CHECK (PLIBSYS_VERSION_MINOR >= 0);
	BOOST_CHECK (PLIBSYS_VERSION_PATCH >= 0);
	BOOST_CHECK (PLIBSYS_VERSION >= 0);

#if !defined (PLIBSYS_VERSION_STR)
	BOOST_CHECK (false);
#endif

	BOOST_CHECK (PLIBSYS_VERSION >= PLIBSYS_VERSION_CHECK (0, 0, 1));

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#ifndef MGF_SCANNER_HPP
#define MGF_SCANNER_HPP

#if ! defined(yyFlexLexerOnce)
#include <mgf/FlexLexer.hpp>
#endif

// Override the interface for yylex since we namespaced it
#undef YY_DECL
#define YY_DECL int mgf::Scanner::yylex()

// Include Bison for types / tokens
#include <mgf/Parser.tab.hh>

namespace mgf
{
    class Parser;
    //typename Parser::semantic_type;

    class Scanner : public yyFlexLexer
    {
        public:
            Scanner(std::istream& in);
            Scanner(const Scanner&) = delete;
            Scanner& operator=(const Scanner&) = delete;

            // save the pointer to yylval so we can change it, and invoke scanner
            int yylex(mgf::Parser::semantic_type *lval);

        protected:

        private:
            // Scanning function created by Flex; make this private to force usage
			// of the overloaded method so we can get a pointer to Bison's yylval
            int yylex();
            /* yyval ptr */
            mgf::Parser::semantic_type *yylval;
    };
}
#endif
<commit_msg>add doc to Scanner<commit_after>#ifndef MGF_SCANNER_HPP
#define MGF_SCANNER_HPP

#if ! defined(yyFlexLexerOnce)
#include <mgf/FlexLexer.hpp>
#endif

// Override the interface for yylex since we namespaced it
#undef YY_DECL
#define YY_DECL int mgf::Scanner::yylex()

// Include Bison for types / tokens
#include <mgf/Parser.tab.hh>

namespace mgf
{
    class Parser;
    //typename Parser::semantic_type;

    /***
     * \brief The lexer that tokenize the input
     */
    class Scanner : public yyFlexLexer
    {
        public:
            /**
             * \brief Construct from a input
             * \param in MGF imput
             */
            Scanner(std::istream& in);
            Scanner(const Scanner&) = delete;
            Scanner& operator=(const Scanner&) = delete;

            /**
             * \breief save the pointer to yylval so we can change it, and invoke scanner
             * \parap lval For Lex/bison
             * \return 0if all input is parse, MGF_END_IONS if end of ion, else, error
             */
            int yylex(mgf::Parser::semantic_type *lval);

        protected:

        private:
            /**
             * \breief Scanning function created by Flex; make this private to force usage
             * of the overloaded method so we can get a pointer to Bison's yylval
             */
            int yylex();
            /* yyval ptr */
            mgf::Parser::semantic_type *yylval; ///< For Lex/bison
    };
}
#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "AnnEventManager.hpp"
#include "AnnDefaultEventListener.hpp"
#include "AnnLogger.hpp"
#include "AnnEngine.hpp"
#include "AnnGetter.hpp"

using namespace Annwvyn;

AnnEventListener::AnnEventListener() :
	player(AnnGetPlayer().get())
{
}

float AnnEventListener::trim(float v, float dz)
{
	//Compute absolute value of v
	auto abs(v);
	if (v < 0) abs = -v;

	//The test is done on the abs value. Return the actual value, or 0 if under the dead-zone
	if (abs >= dz) return v;
	return 0.0f;
}

std::shared_ptr<AnnEventListener> AnnEventListener::getSharedListener()
{
	return shared_from_this();
}

AnnTextInputer::AnnTextInputer() :
	listen(false),
	asciiOnly{ true }
{
}

bool AnnTextInputer::keyPressed(const OIS::KeyEvent &arg)
{
	if (!listen) return true;
	//If backspace, pop last char if possible
	if (arg.key == OIS::KC_BACK && !input.empty())
		input.pop_back();
	else if (arg.text < 127 && arg.text > 31 || arg.text == 13 || !asciiOnly)
		//Put typed char into the application
		input.push_back(char(arg.text));
	return true;
}

bool AnnTextInputer::keyReleased(const OIS::KeyEvent &arg)
{
	return true;
}

std::string AnnTextInputer::getInput() const
{
	return input;
}

void AnnTextInputer::clearInput()
{
	input.clear();
}

void AnnTextInputer::startListening()
{
	clearInput();
	listen = true;
}

void AnnTextInputer::stopListening()
{
	listen = false;
}

void AnnTextInputer::setInput(std::string content)
{
	input = content;
}

AnnEventManager::AnnEventManager(Ogre::RenderWindow* w) : AnnSubSystem("EventManager"),
Keyboard(nullptr),
Mouse(nullptr),
lastTimerCreated(0),
defaultEventListener(nullptr),
knowXbox(false),
keyboardIgnore{ false }
{
	//Reserve some memory
	keyEventBuffer.reserve(10);
	mouseEventBuffer.reserve(10);
	stickEventBuffer.reserve(10);
	handControllerEventBuffer.reserve(10);

	//Init all bool array to false
	for (auto& keyState : previousKeyStates) keyState = false;
	for (auto& mouseButtonState : previousMouseButtonStates) mouseButtonState = false;

	//Configure and create the input system
	size_t windowHnd;
	w->getCustomAttribute("WINDOW", &windowHnd);
	pl.insert(make_pair(std::string("WINDOW"), std::to_string(windowHnd)));
	InputManager = OIS::InputManager::createInputSystem(pl);

	//Get the keyboard, mouse and joysticks objects
	Keyboard = static_cast<OIS::Keyboard*>(InputManager->createInputObject(OIS::OISKeyboard, true));
	Mouse = static_cast<OIS::Mouse*>(InputManager->createInputObject(OIS::OISMouse, true));
	for (auto nbStick(0); nbStick < InputManager->getNumberOfDevices(OIS::OISJoyStick); nbStick++)
	{
		//Create joystick object
		auto Joystick = static_cast<OIS::JoyStick*>(InputManager->createInputObject(OIS::OISJoyStick, true));
		Joysticks.push_back(new JoystickBuffer(Joystick));
		AnnDebug() << "Detected joystick : " << Joystick->vendor();

		//Test for the stick being an Xbox controller (Oculus, and PC in general uses Xbox as *standard* controller)
		if (Joystick->vendor().find("Xbox") != std::string::npos ||
			Joystick->vendor().find("XBOX") != std::string::npos)
		{
			knowXbox = true;
			xboxID = StickAxisId(Joystick->getID());
			AnnDebug() << "Detected Xbox controller at ID " << xboxID;
		}
	}

	textInputer = std::make_unique<AnnTextInputer>();
	Keyboard->setEventCallback(textInputer.get());
}

AnnTextInputer* AnnEventManager::getTextInputer() const
{
	return textInputer.get();
}

AnnEventManager::~AnnEventManager()
{
	clearListenerList();
	defaultEventListener = nullptr;
	Keyboard->setEventCallback(nullptr);
	delete Keyboard;
	delete Mouse;
	for (auto Joystick : Joysticks)
		delete Joystick;
	Joysticks.clear();
}

void AnnEventManager::useDefaultEventListener()
{
	AnnDebug("Reconfiguring the engine to use the default event listener");
	AnnDebug("This unregister any current listener in use!");

	//Remove all event listeners
	removeListener();

	//If the event listener isn't already initialized, allocate one
	if (!defaultEventListener)
		defaultEventListener = std::make_shared<AnnDefaultEventListener>();

	//Set the default event listener to the event manager
	addListener(defaultEventListener);
}

std::shared_ptr<AnnEventListener> AnnEventManager::getDefaultEventListener() const
{
	return defaultEventListener;
}

void AnnEventManager::addListener(std::shared_ptr<AnnEventListener> l)
{
	AnnDebug() << "Adding an event listener : " << l.get();
	if (l != nullptr)
		listeners.push_back(l);
}

void AnnEventManager::clearListenerList()
{
	listeners.clear();
}

//l equals NULL by default
void AnnEventManager::removeListener(std::shared_ptr<AnnEventListener> l)
{
	AnnDebug() << "Removing an event listener : " << l.get();
	if (l == nullptr) { clearListenerList(); return; }

	//TODO write this with better
	auto iterator = listeners.begin();
	while (iterator != listeners.end())
		if ((*iterator).lock() && (*iterator).lock().get() == l.get())
			iterator = listeners.erase(iterator);
		else ++iterator;
}

void AnnEventManager::update()
{
	processCollisionEvents();
	processInput();
	processTriggerEvents();
	processTimers();
	processUserSpaceEvents();
}

unsigned int JoystickBuffer::idcounter = 0;

void AnnEventManager::captureEvents()
{
	//Capture events
	Keyboard->capture();
	Mouse->capture();

	for (auto& joystick : Joysticks)
		joystick->stick->capture();
}

void AnnEventManager::processKeyboardEvents()
{
	//for each key of the keyboard
	for (size_t c(0); c < KeyCode::SIZE; c++)
		if (Keyboard->isKeyDown(OIS::KeyCode(c)) && !previousKeyStates[c] ||
			!Keyboard->isKeyDown(OIS::KeyCode(c)) && previousKeyStates[c])
		{
			//create a corresponding key event
			AnnKeyEvent e;
			e.setCode(KeyCode::code(c));
			e.ignored = keyboardIgnore;
			bool(previousKeyStates[c] = Keyboard->isKeyDown(OIS::KeyCode(c))) ? e.setPressed() : e.setReleased();

			keyEventBuffer.push_back(e);
		}
}

void AnnEventManager::processMouseEvents()
{
	auto state(Mouse->getMouseState());

	AnnMouseEvent e;

	for (size_t i(0); i < nbButtons; i++)
		e.setButtonStatus(MouseButtonId(i), state.buttonDown(OIS::MouseButtonID(i)));

	e.setAxisInformation(X, AnnMouseAxis(X, state.X.rel, state.X.abs));
	e.setAxisInformation(Y, AnnMouseAxis(Y, state.Y.rel, state.Y.abs));
	e.setAxisInformation(Z, AnnMouseAxis(Z, state.Z.rel, state.Z.abs));

	mouseEventBuffer.push_back(e);
}

void AnnEventManager::processJoystickEvents()
{
	for (auto Joystick : Joysticks)
	{
		const auto& state(Joystick->stick->getJoyStickState());
		AnnStickEvent e;

		//Get all buttons immediate data
		e.buttons = state.mButtons;

		//Get all axes immediate data
		for (auto i(0u); i < state.mAxes.size(); i++)
		{
			AnnStickAxis axis(i, state.mAxes[i].rel, state.mAxes[i].abs);
			if (state.mAxes[i].absOnly)
				axis.noRel = true;
			e.axes.push_back(axis);
		}

		//The joystick state object always have 4 Pov but the AnnStickEvent has the number of Pov the stick has
		for (size_t i(0); i < Joystick->stick->getNumberOfComponents(OIS::ComponentType::OIS_POV); i++)
			e.povs.push_back(AnnStickPov(state.mPOV[i].direction));

		//Get press and release event lists
		for (unsigned short i(0); i < state.mButtons.size() && i < Joystick->previousStickButtonStates.size(); i++)
			if (!Joystick->previousStickButtonStates[i] && state.mButtons[i])
				e.pressed.push_back(i);
			else if (Joystick->previousStickButtonStates[i] && !state.mButtons[i])
				e.released.push_back(i);

		//Save current buttons state for next frame
		Joystick->previousStickButtonStates = state.mButtons;
		e.vendor = Joystick->stick->vendor();
		e.stickID = Joystick->getID();
		if (knowXbox)
			if (e.stickID == xboxID)
				e.xbox = true;

		stickEventBuffer.push_back(e);
	}
}

void AnnEventManager::processHandControllerEvents()
{
	if (AnnGetVRRenderer()->handControllersAvailable())
	{
		for (auto handController : AnnGetVRRenderer()->getHandControllerArray())
		{
			if (!handController) continue;
			AnnHandControllerEvent e;
			e.sender = handController.get();

			handControllerEventBuffer.push_back(e);
		}
	}
}

void AnnEventManager::pushEventsToListeners()
{
	for (auto& weak_listener : listeners) if (auto listener = weak_listener.lock())
	{
		for (auto& e : keyEventBuffer) listener->KeyEvent(e);
		for (auto& e : mouseEventBuffer) listener->MouseEvent(e);
		for (auto& e : stickEventBuffer) listener->StickEvent(e);
		for (auto& e : handControllerEventBuffer) listener->HandControllerEvent(e);

		listener->tick();
	}

	keyEventBuffer.clear();
	mouseEventBuffer.clear();
	stickEventBuffer.clear();
	handControllerEventBuffer.clear();
}

void AnnEventManager::processInput()
{
	captureEvents();
	processKeyboardEvents();
	processMouseEvents();
	processJoystickEvents();
	processHandControllerEvents();
	pushEventsToListeners();
}

timerID AnnEventManager::fireTimerMillisec(double delay)
{
	auto newID = lastTimerCreated++;
	futureTimers.push_back(AnnTimer(newID, delay));
	return newID;
}

timerID AnnEventManager::fireTimer(double delay)
{
	return fireTimerMillisec(1000 * delay);
}

void AnnEventManager::processTimers()
{
	//Append timers
	for (const auto& futureTimer : futureTimers)
		activeTimers.push_back(futureTimer);
	futureTimers.clear();

	//Send events
	for (auto weak_listener : listeners) if (auto listener = weak_listener.lock())
		for (const auto& timer : activeTimers)
			if (timer.isTimeout()) listener->TimeEvent({ timer });

	//Cleanup
	std::remove_if(activeTimers.begin(), activeTimers.end(),
		[&](const AnnTimer& timer) {return timer.isTimeout(); });
}

void AnnEventManager::processTriggerEvents()
{
	for (const auto& triggerEvent : triggerEventBuffer)
		for (auto weakListener : listeners) if (auto listener = weakListener.lock())
			listener->TriggerEvent(triggerEvent);

	triggerEventBuffer.clear();
}

void AnnEventManager::processCollisionEvents()
{
	for (auto weakListener : listeners) if (auto listener = weakListener.lock())
	{
		for (auto& collisionPair : collisionBuffer)
		{
			const auto aMov = static_cast<AnnAbstractMovable*>(collisionPair.first);
			const auto bMov = static_cast<AnnAbstractMovable*>(collisionPair.second);
			if (auto a = dynamic_cast<AnnGameObject*>(aMov)) if (auto b = dynamic_cast<AnnGameObject*>(bMov))
			{
				AnnCollisionEvent e{ a, b };
				listener->CollisionEvent(e);
			}
		}

		for (auto playerCollision : playerCollisionBuffer)
		{
			AnnPlayerCollisionEvent e{ playerCollision };
			listener->PlayerCollisionEvent(e);
		}
	}

	collisionBuffer.clear();
	playerCollisionBuffer.clear();
}

size_t AnnEventManager::getNbStick() const
{
	return Joysticks.size();
}

AnnEventListener::~AnnEventListener()
{
}

void AnnEventManager::detectedCollision(void* a, void* b)
{
	//The only body that doesn't have an "userPointer" set is the Player's rigidbody.
	//If one of the pair is null, it's a player collision that has been detected on this manifold.
	//Not an object-object collision
	if (!a) return playerCollision(b);
	if (!b) return playerCollision(a);

	//push the object-object collision in the buffer
	collisionBuffer.push_back(std::make_pair(a, b));
}

void AnnEventManager::playerCollision(void* object)
{
	auto movable = static_cast<AnnAbstractMovable*>(object);
	if (auto gameObject = dynamic_cast<AnnGameObject*>(movable))
	{
		playerCollisionBuffer.push_back(gameObject);
	}
	else if (auto triggerObject = dynamic_cast<AnnTriggerObject*>(movable))
	{
		AnnTriggerEvent e;
		e.sender = triggerObject;
		e.contact = true;
		triggerEventBuffer.push_back(e);
	}
}

void AnnEventManager::keyboardUsedForText(bool state)
{
	keyboardIgnore = state;
}

void AnnEventManager::userSpaceDispatchEvent(std::shared_ptr<AnnUserSpaceEvent> e, AnnUserSpaceEventLauncher* l)
{
	userSpaceEventBuffer.push_back(make_pair(e, l));
}

void AnnEventManager::processUserSpaceEvents()
{
	for (auto userSpaceEvent : userSpaceEventBuffer)
	{
		for (auto weakListener : listeners) if (auto listener = weakListener.lock())
			listener->EventFromUserSubsystem(*userSpaceEvent.first, userSpaceEvent.second);
	}
	userSpaceEventBuffer.clear();
}<commit_msg>cleanup listener removal code with std::remove_if<commit_after>#include "stdafx.h"
#include "AnnEventManager.hpp"
#include "AnnDefaultEventListener.hpp"
#include "AnnLogger.hpp"
#include "AnnEngine.hpp"
#include "AnnGetter.hpp"

using namespace Annwvyn;

AnnEventListener::AnnEventListener() :
	player(AnnGetPlayer().get())
{
}

float AnnEventListener::trim(float v, float dz)
{
	//Compute absolute value of v
	auto abs(v);
	if (v < 0) abs = -v;

	//The test is done on the abs value. Return the actual value, or 0 if under the dead-zone
	if (abs >= dz) return v;
	return 0.0f;
}

std::shared_ptr<AnnEventListener> AnnEventListener::getSharedListener()
{
	return shared_from_this();
}

AnnTextInputer::AnnTextInputer() :
	listen(false),
	asciiOnly{ true }
{
}

bool AnnTextInputer::keyPressed(const OIS::KeyEvent &arg)
{
	if (!listen) return true;
	//If backspace, pop last char if possible
	if (arg.key == OIS::KC_BACK && !input.empty())
		input.pop_back();
	else if (arg.text < 127 && arg.text > 31 || arg.text == 13 || !asciiOnly)
		//Put typed char into the application
		input.push_back(char(arg.text));
	return true;
}

bool AnnTextInputer::keyReleased(const OIS::KeyEvent &arg)
{
	return true;
}

std::string AnnTextInputer::getInput() const
{
	return input;
}

void AnnTextInputer::clearInput()
{
	input.clear();
}

void AnnTextInputer::startListening()
{
	clearInput();
	listen = true;
}

void AnnTextInputer::stopListening()
{
	listen = false;
}

void AnnTextInputer::setInput(std::string content)
{
	input = content;
}

AnnEventManager::AnnEventManager(Ogre::RenderWindow* w) : AnnSubSystem("EventManager"),
Keyboard(nullptr),
Mouse(nullptr),
lastTimerCreated(0),
defaultEventListener(nullptr),
knowXbox(false),
keyboardIgnore{ false }
{
	//Reserve some memory
	keyEventBuffer.reserve(10);
	mouseEventBuffer.reserve(10);
	stickEventBuffer.reserve(10);
	handControllerEventBuffer.reserve(10);

	//Init all bool array to false
	for (auto& keyState : previousKeyStates) keyState = false;
	for (auto& mouseButtonState : previousMouseButtonStates) mouseButtonState = false;

	//Configure and create the input system
	size_t windowHnd;
	w->getCustomAttribute("WINDOW", &windowHnd);
	pl.insert(make_pair(std::string("WINDOW"), std::to_string(windowHnd)));
	InputManager = OIS::InputManager::createInputSystem(pl);

	//Get the keyboard, mouse and joysticks objects
	Keyboard = static_cast<OIS::Keyboard*>(InputManager->createInputObject(OIS::OISKeyboard, true));
	Mouse = static_cast<OIS::Mouse*>(InputManager->createInputObject(OIS::OISMouse, true));
	for (auto nbStick(0); nbStick < InputManager->getNumberOfDevices(OIS::OISJoyStick); nbStick++)
	{
		//Create joystick object
		auto Joystick = static_cast<OIS::JoyStick*>(InputManager->createInputObject(OIS::OISJoyStick, true));
		Joysticks.push_back(new JoystickBuffer(Joystick));
		AnnDebug() << "Detected joystick : " << Joystick->vendor();

		//Test for the stick being an Xbox controller (Oculus, and PC in general uses Xbox as *standard* controller)
		if (Joystick->vendor().find("Xbox") != std::string::npos ||
			Joystick->vendor().find("XBOX") != std::string::npos)
		{
			knowXbox = true;
			xboxID = StickAxisId(Joystick->getID());
			AnnDebug() << "Detected Xbox controller at ID " << xboxID;
		}
	}

	textInputer = std::make_unique<AnnTextInputer>();
	Keyboard->setEventCallback(textInputer.get());
}

AnnTextInputer* AnnEventManager::getTextInputer() const
{
	return textInputer.get();
}

AnnEventManager::~AnnEventManager()
{
	clearListenerList();
	defaultEventListener = nullptr;
	Keyboard->setEventCallback(nullptr);
	delete Keyboard;
	delete Mouse;
	for (auto Joystick : Joysticks)
		delete Joystick;
	Joysticks.clear();
}

void AnnEventManager::useDefaultEventListener()
{
	AnnDebug("Reconfiguring the engine to use the default event listener");
	AnnDebug("This unregister any current listener in use!");

	//Remove all event listeners
	removeListener();

	//If the event listener isn't already initialized, allocate one
	if (!defaultEventListener)
		defaultEventListener = std::make_shared<AnnDefaultEventListener>();

	//Set the default event listener to the event manager
	addListener(defaultEventListener);
}

std::shared_ptr<AnnEventListener> AnnEventManager::getDefaultEventListener() const
{
	return defaultEventListener;
}

void AnnEventManager::addListener(std::shared_ptr<AnnEventListener> l)
{
	AnnDebug() << "Adding an event listener : " << l.get();
	if (l != nullptr)
		listeners.push_back(l);
}

void AnnEventManager::clearListenerList()
{
	listeners.clear();
}

//l equals NULL by default
void AnnEventManager::removeListener(std::shared_ptr<AnnEventListener> l)
{
	AnnDebug() << "Removing an event listener : " << l.get();
	if (l == nullptr) { clearListenerList(); return; }

	std::remove_if(listeners.begin(), listeners.end(),
		[&](std::weak_ptr<AnnEventListener> weak_listener)
	{
		if (auto listener = weak_listener.lock()) return listener == l;
		return false;
	});
}

void AnnEventManager::update()
{
	processCollisionEvents();
	processInput();
	processTriggerEvents();
	processTimers();
	processUserSpaceEvents();
}

unsigned int JoystickBuffer::idcounter = 0;

void AnnEventManager::captureEvents()
{
	//Capture events
	Keyboard->capture();
	Mouse->capture();

	for (auto& joystick : Joysticks)
		joystick->stick->capture();
}

void AnnEventManager::processKeyboardEvents()
{
	//for each key of the keyboard
	for (size_t c(0); c < KeyCode::SIZE; c++)
		if (Keyboard->isKeyDown(OIS::KeyCode(c)) && !previousKeyStates[c] ||
			!Keyboard->isKeyDown(OIS::KeyCode(c)) && previousKeyStates[c])
		{
			//create a corresponding key event
			AnnKeyEvent e;
			e.setCode(KeyCode::code(c));
			e.ignored = keyboardIgnore;
			bool(previousKeyStates[c] = Keyboard->isKeyDown(OIS::KeyCode(c))) ? e.setPressed() : e.setReleased();

			keyEventBuffer.push_back(e);
		}
}

void AnnEventManager::processMouseEvents()
{
	auto state(Mouse->getMouseState());

	AnnMouseEvent e;

	for (size_t i(0); i < nbButtons; i++)
		e.setButtonStatus(MouseButtonId(i), state.buttonDown(OIS::MouseButtonID(i)));

	e.setAxisInformation(X, AnnMouseAxis(X, state.X.rel, state.X.abs));
	e.setAxisInformation(Y, AnnMouseAxis(Y, state.Y.rel, state.Y.abs));
	e.setAxisInformation(Z, AnnMouseAxis(Z, state.Z.rel, state.Z.abs));

	mouseEventBuffer.push_back(e);
}

void AnnEventManager::processJoystickEvents()
{
	for (auto Joystick : Joysticks)
	{
		const auto& state(Joystick->stick->getJoyStickState());
		AnnStickEvent e;

		//Get all buttons immediate data
		e.buttons = state.mButtons;

		//Get all axes immediate data
		for (auto i(0u); i < state.mAxes.size(); i++)
		{
			AnnStickAxis axis(i, state.mAxes[i].rel, state.mAxes[i].abs);
			if (state.mAxes[i].absOnly)
				axis.noRel = true;
			e.axes.push_back(axis);
		}

		//The joystick state object always have 4 Pov but the AnnStickEvent has the number of Pov the stick has
		for (size_t i(0); i < Joystick->stick->getNumberOfComponents(OIS::ComponentType::OIS_POV); i++)
			e.povs.push_back(AnnStickPov(state.mPOV[i].direction));

		//Get press and release event lists
		for (unsigned short i(0); i < state.mButtons.size() && i < Joystick->previousStickButtonStates.size(); i++)
			if (!Joystick->previousStickButtonStates[i] && state.mButtons[i])
				e.pressed.push_back(i);
			else if (Joystick->previousStickButtonStates[i] && !state.mButtons[i])
				e.released.push_back(i);

		//Save current buttons state for next frame
		Joystick->previousStickButtonStates = state.mButtons;
		e.vendor = Joystick->stick->vendor();
		e.stickID = Joystick->getID();
		if (knowXbox)
			if (e.stickID == xboxID)
				e.xbox = true;

		stickEventBuffer.push_back(e);
	}
}

void AnnEventManager::processHandControllerEvents()
{
	if (AnnGetVRRenderer()->handControllersAvailable())
	{
		for (auto handController : AnnGetVRRenderer()->getHandControllerArray())
		{
			if (!handController) continue;
			AnnHandControllerEvent e;
			e.sender = handController.get();

			handControllerEventBuffer.push_back(e);
		}
	}
}

void AnnEventManager::pushEventsToListeners()
{
	for (auto& weak_listener : listeners) if (auto listener = weak_listener.lock())
	{
		for (auto& e : keyEventBuffer) listener->KeyEvent(e);
		for (auto& e : mouseEventBuffer) listener->MouseEvent(e);
		for (auto& e : stickEventBuffer) listener->StickEvent(e);
		for (auto& e : handControllerEventBuffer) listener->HandControllerEvent(e);

		listener->tick();
	}

	keyEventBuffer.clear();
	mouseEventBuffer.clear();
	stickEventBuffer.clear();
	handControllerEventBuffer.clear();
}

void AnnEventManager::processInput()
{
	captureEvents();
	processKeyboardEvents();
	processMouseEvents();
	processJoystickEvents();
	processHandControllerEvents();
	pushEventsToListeners();
}

timerID AnnEventManager::fireTimerMillisec(double delay)
{
	auto newID = lastTimerCreated++;
	futureTimers.push_back(AnnTimer(newID, delay));
	return newID;
}

timerID AnnEventManager::fireTimer(double delay)
{
	return fireTimerMillisec(1000 * delay);
}

void AnnEventManager::processTimers()
{
	//Append timers
	for (const auto& futureTimer : futureTimers)
		activeTimers.push_back(futureTimer);
	futureTimers.clear();

	//Send events
	for (auto weak_listener : listeners) if (auto listener = weak_listener.lock())
		for (const auto& timer : activeTimers)
			if (timer.isTimeout()) listener->TimeEvent({ timer });

	//Cleanup
	std::remove_if(activeTimers.begin(), activeTimers.end(),
		[&](const AnnTimer& timer) {return timer.isTimeout(); });
}

void AnnEventManager::processTriggerEvents()
{
	for (const auto& triggerEvent : triggerEventBuffer)
		for (auto weakListener : listeners) if (auto listener = weakListener.lock())
			listener->TriggerEvent(triggerEvent);

	triggerEventBuffer.clear();
}

void AnnEventManager::processCollisionEvents()
{
	for (auto weakListener : listeners) if (auto listener = weakListener.lock())
	{
		for (auto& collisionPair : collisionBuffer)
		{
			const auto aMov = static_cast<AnnAbstractMovable*>(collisionPair.first);
			const auto bMov = static_cast<AnnAbstractMovable*>(collisionPair.second);
			if (auto a = dynamic_cast<AnnGameObject*>(aMov)) if (auto b = dynamic_cast<AnnGameObject*>(bMov))
			{
				AnnCollisionEvent e{ a, b };
				listener->CollisionEvent(e);
			}
		}

		for (auto playerCollision : playerCollisionBuffer)
		{
			AnnPlayerCollisionEvent e{ playerCollision };
			listener->PlayerCollisionEvent(e);
		}
	}

	collisionBuffer.clear();
	playerCollisionBuffer.clear();
}

size_t AnnEventManager::getNbStick() const
{
	return Joysticks.size();
}

AnnEventListener::~AnnEventListener()
{
}

void AnnEventManager::detectedCollision(void* a, void* b)
{
	//The only body that doesn't have an "userPointer" set is the Player's rigidbody.
	//If one of the pair is null, it's a player collision that has been detected on this manifold.
	//Not an object-object collision
	if (!a) return playerCollision(b);
	if (!b) return playerCollision(a);

	//push the object-object collision in the buffer
	collisionBuffer.push_back(std::make_pair(a, b));
}

void AnnEventManager::playerCollision(void* object)
{
	auto movable = static_cast<AnnAbstractMovable*>(object);
	if (auto gameObject = dynamic_cast<AnnGameObject*>(movable))
	{
		playerCollisionBuffer.push_back(gameObject);
	}
	else if (auto triggerObject = dynamic_cast<AnnTriggerObject*>(movable))
	{
		AnnTriggerEvent e;
		e.sender = triggerObject;
		e.contact = true;
		triggerEventBuffer.push_back(e);
	}
}

void AnnEventManager::keyboardUsedForText(bool state)
{
	keyboardIgnore = state;
}

void AnnEventManager::userSpaceDispatchEvent(std::shared_ptr<AnnUserSpaceEvent> e, AnnUserSpaceEventLauncher* l)
{
	userSpaceEventBuffer.push_back(make_pair(e, l));
}

void AnnEventManager::processUserSpaceEvents()
{
	for (auto userSpaceEvent : userSpaceEventBuffer)
	{
		for (auto weakListener : listeners) if (auto listener = weakListener.lock())
			listener->EventFromUserSubsystem(*userSpaceEvent.first, userSpaceEvent.second);
	}
	userSpaceEventBuffer.clear();
}<|endoftext|>


<commit_before>#include <gbAudio/impl/AudioDevice_OAL.hpp>

#include <gbAudio/Exceptions.hpp>

#include <gbBase/UnusedVariable.hpp>

#include <al.h>
#include <alc.h>

// ALC_ALL_DEVICES_SPECIFIER is an extension that might not be defined everywhere
#ifndef ALC_ALL_DEVICES_SPECIFIER
#   define ALC_ALL_DEVICES_SPECIFIER 0
#endif

namespace GHULBUS_AUDIO_NAMESPACE
{
namespace impl
{
AudioDevice_OAL::AudioDevice_OAL(AudioDevice::DeviceIdentifier const& device_id)
{
    // @todo
    GHULBUS_UNUSED_VARIABLE(device_id);
}

AudioDevice_OAL::~AudioDevice_OAL()
{
    // @todo
}

std::vector<AudioDevice::ChannelFormat> AudioDevice_OAL::getSupportedChannelFormats() const
{
    std::vector<ChannelFormat> ret;
    ret.push_back(ChannelFormat::Mono);
    ret.push_back(ChannelFormat::Stereo);
    if(alGetEnumValue("AL_FORMAT_QUAD16"))  { ret.push_back(ChannelFormat::MC_Quad); }
    if(alGetEnumValue("AL_FORMAT_51CHN16")) { ret.push_back(ChannelFormat::MC_5_1); }
    if(alGetEnumValue("AL_FORMAT_61CHN16")) { ret.push_back(ChannelFormat::MC_6_1); }
    if(alGetEnumValue("AL_FORMAT_71CHN16")) { ret.push_back(ChannelFormat::MC_7_1); }
    return ret;
}

AudioBackend AudioDevice_OAL::getBackend() const
{
    return AudioBackend::OpenAL;
}

/* static */ std::vector<AudioDevice::DeviceIdentifier> AudioDevice_OAL::enumerateDevices_OAL()
{
    if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") != ALC_TRUE) {
        GHULBUS_THROW(Exceptions::IOError(), "Device enumeration not supported.");
    }
    ALCchar const* device_names =
        (alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") == ALC_TRUE) ?
        alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER) :
        alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
    // device names is a concatenation of zero terminated strings;
    // the end of the list is designated by an empty string.
    std::vector<DeviceIdentifier> ret;
    for(;;) {
        DeviceIdentifier devid;
        devid.name = device_names;
        if(devid.name.empty()) { break; }
        ret.push_back(devid);
        device_names += ret.back().name.length() + 1;
    }
    return ret;
}
}
}
<commit_msg>slightly cleaner solution to the missing ALC_ALL_DEVICES_SPECIFIER<commit_after>#include <gbAudio/impl/AudioDevice_OAL.hpp>

#include <gbAudio/Exceptions.hpp>

#include <gbBase/UnusedVariable.hpp>

#include <al.h>
#include <alc.h>

namespace GHULBUS_AUDIO_NAMESPACE
{
namespace impl
{
AudioDevice_OAL::AudioDevice_OAL(AudioDevice::DeviceIdentifier const& device_id)
{
    // @todo
    GHULBUS_UNUSED_VARIABLE(device_id);
}

AudioDevice_OAL::~AudioDevice_OAL()
{
    // @todo
}

std::vector<AudioDevice::ChannelFormat> AudioDevice_OAL::getSupportedChannelFormats() const
{
    std::vector<ChannelFormat> ret;
    ret.push_back(ChannelFormat::Mono);
    ret.push_back(ChannelFormat::Stereo);
    if(alGetEnumValue("AL_FORMAT_QUAD16"))  { ret.push_back(ChannelFormat::MC_Quad); }
    if(alGetEnumValue("AL_FORMAT_51CHN16")) { ret.push_back(ChannelFormat::MC_5_1); }
    if(alGetEnumValue("AL_FORMAT_61CHN16")) { ret.push_back(ChannelFormat::MC_6_1); }
    if(alGetEnumValue("AL_FORMAT_71CHN16")) { ret.push_back(ChannelFormat::MC_7_1); }
    return ret;
}

AudioBackend AudioDevice_OAL::getBackend() const
{
    return AudioBackend::OpenAL;
}

/* static */ std::vector<AudioDevice::DeviceIdentifier> AudioDevice_OAL::enumerateDevices_OAL()
{
    if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") != ALC_TRUE) {
        GHULBUS_THROW(Exceptions::IOError(), "Device enumeration not supported.");
    }
    ALCchar const* device_names =
#ifdef ALC_ALL_DEVICES_SPECIFIER
        (alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") == ALC_TRUE) ?
            alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER) :
#endif
        alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
    // device names is a concatenation of zero terminated strings;
    // the end of the list is designated by an empty string.
    std::vector<DeviceIdentifier> ret;
    for(;;) {
        DeviceIdentifier devid;
        devid.name = device_names;
        if(devid.name.empty()) { break; }
        ret.push_back(devid);
        device_names += ret.back().name.length() + 1;
    }
    return ret;
}
}
}
<|endoftext|>


<commit_before>#include <QClipboard>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QHash>
#include <QKeyEvent>
#include <QLineEdit>
#include <QList>
#include <QMessageBox>
#include <QPoint>
#include <QSettings>
#include <QSize>
#include <QTextStream>
#include <QVector>
#include <XSLTransformer.hh>

#include <stdexcept>
#include <typeinfo>

#include "BracketedDelegate.hh"
#include "BracketedColorDelegate.hh"
#include "BracketedKeywordInContextDelegate.hh"
#include "BracketedVisibilityDelegate.hh"
#include "BracketedWindow.hh"
#include "CorpusWidget.hh"
#include "DactMacrosModel.hh"
#include "FilterModel.hh"
#include "Query.hh"
#include "ValidityColor.hh"
#include "ui_BracketedWindow.h"

namespace ac = alpinocorpus;

BracketedWindow::BracketedWindow(QWidget *parent) :
    CorpusWidget(parent),
    d_ui(QSharedPointer<Ui::BracketedWindow>(new Ui::BracketedWindow))
{
    d_ui->setupUi(this);

    initListDelegates();
    createActions();
    readSettings();
}

BracketedWindow::~BracketedWindow()
{
    writeSettings();
}

void BracketedWindow::cancelQuery()
{
    if (d_model)
        d_model->cancelQuery();
}

void BracketedWindow::colorChanged()
{
    reloadListDelegate();
}

void BracketedWindow::queryFailed(QString error)
{
    progressStopped(0, 0);

    QMessageBox::critical(this, tr("Error processing query"),
        tr("Could not process query: ") + error,
        QMessageBox::Ok);
}

void BracketedWindow::switchCorpus(QSharedPointer<ac::CorpusReader> corpusReader)
{
    d_corpusReader = corpusReader;
    emit saveStateChanged();
}

void BracketedWindow::setFilter(QString const &filter, QString const &raw_filter)
{
    Q_UNUSED(raw_filter);

    d_filter = filter;
    startQuery();
}

void BracketedWindow::setModel(FilterModel *model)
{
    d_model = QSharedPointer<FilterModel>(model);
    d_ui->resultsTable->setModel(d_model.data());

    emit saveStateChanged();

    //d_ui->resultsTable->setColumnHidden(1, true);

    //d_ui->resultsTable->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
    //d_ui->resultsTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
    //d_ui->resultsTable->horizontalHeader()->setResizeMode(2, QHeaderView::ResizeToContents);

    d_ui->resultsTable->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    d_ui->resultsTable->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    d_ui->resultsTable->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);

    // disables horizontal jumping when a sentence is selected
    d_ui->resultsTable->setAutoScroll(false);

    /*
    connect(d_model.data(), SIGNAL(queryEntryFound(QString)),
        this, SLOT(updateResultsTotalCount()));
    */

    connect(d_model.data(), SIGNAL(queryFailed(QString)),
        SLOT(queryFailed(QString)));

    connect(d_model.data(), SIGNAL(queryStarted(int)),
        SLOT(progressStarted(int)));

    connect(d_model.data(), SIGNAL(queryStopped(int, int)),
        SLOT(progressStopped(int, int)));

    connect(d_model.data(), SIGNAL(queryFinished(int, int, bool)),
            SLOT(progressFinished(int, int, bool)));

}

void BracketedWindow::startQuery()
{
    // XXX - only once
    QFile file(":/stylesheets/bracketed-sentence-xml.xsl");
    file.open(QIODevice::ReadOnly);
    QTextStream xslStream(&file);
    QString stylesheet = xslStream.readAll();

    if (d_filter.trimmed().isEmpty())
        setModel(new FilterModel(QSharedPointer<ac::CorpusReader>()));
    else
        setModel(new FilterModel(d_corpusReader));

    // Reload the list delegate since they keep their results cached.
    // This will make sure no old cached data is used.
    reloadListDelegate();

    // This would be the correct manner to execute the query:
    //
    //d_model->runQuery(generateQuery(d_filter, "(@cat or @root)"),
    //  stylesheet);
    //
    // However, in some cases this will result in an insanely slow
    // query (#68). So, we now execute the query as-is, and in the
    // stylesheets only use the matching nodes that have a @cat or
    // @root attribute. Theoretically, this could lead to the addition
    // of sentences to the model where nothing is bracketed. If this
    // happens, this is the place to start looking.

    d_model->runQuery(d_filter, stylesheet);

    showFilenamesChanged();
}

void BracketedWindow::applyValidityColor(QString const &)
{
    ::applyValidityColor(sender());
}

void BracketedWindow::createActions()
{
    /*
    QObject::connect(d_ui->resultsListWidget,
        SIGNAL(currentItemChanged(QListWidgetItem *,QListWidgetItem *)),
        this,
        SLOT(entrySelected(QListWidgetItem*,QListWidgetItem*)));
    */

    QObject::connect(d_ui->resultsTable,
        // itemActivated is triggered by a single click on some systems
        // where this is the configured behavior: it can be annoying.
        // But it also enables using [enter] to raise the main window
        // which is the expected/preferred behavior.
        SIGNAL(activated(QModelIndex const &)),
        this,
        SLOT(entryActivated(QModelIndex const &)));

    QObject::connect(d_ui->listDelegateComboBox, SIGNAL(currentIndexChanged(int)),
        this, SLOT(listDelegateChanged(int)));

    connect(d_ui->filenamesCheckBox, SIGNAL(toggled(bool)),
        SLOT(showFilenamesChanged()));
}

void BracketedWindow::showFilenames(bool show)
{
   d_ui->resultsTable->setColumnHidden(0, !show);
   d_ui->resultsTable->setColumnHidden(1, !show);
   d_ui->filenamesCheckBox->setChecked(show);
}

void BracketedWindow::showFilenamesChanged()
{
    showFilenames(d_ui->filenamesCheckBox->isChecked());
}

/*
void BracketedWindow::entrySelected(QListWidgetItem *current, QListWidgetItem *)
{
    if (current == 0)
        return;

    emit currentEntryChanged(current->data(Qt::UserRole).toString());

    // Raises this window again when using cursor keys after using
    // [enter] to raise the main window.
    raise();
}
*/

void BracketedWindow::entryActivated(QModelIndex const &index)
{
    emit entryActivated(index.sibling(index.row(), 0).data(Qt::UserRole).toString());
}

void BracketedWindow::addOutputType(QString const &outputType,
    QString const &description, DelegateFactory factory)
{
    d_outputTypes.append(outputType);
    d_ui->listDelegateComboBox->addItem(description,
        d_listDelegateFactories.size());
    d_listDelegateFactories.append(factory);
}

void BracketedWindow::listDelegateChanged(int index)
{
    int delegateIndex = d_ui->listDelegateComboBox->itemData(index, Qt::UserRole).toInt();

    if (delegateIndex >= d_listDelegateFactories.size())
    {
        qWarning() << QString("Trying to select a list delegate (%1) beyond the boundary "
                              "of the d_listDelegateFactories list (%2)")
                             .arg(delegateIndex).arg(d_listDelegateFactories.size());
        return;
    }

    QAbstractItemDelegate* prevItemDelegate = d_ui->resultsTable->itemDelegateForColumn(2);
    d_ui->resultsTable->setItemDelegateForColumn(2, d_listDelegateFactories[delegateIndex](d_corpusReader));
    delete prevItemDelegate;
    d_ui->resultsTable->resizeRowsToContents();
}

void BracketedWindow::initListDelegates()
{
    addOutputType("sentence", "Complete sentence",
        &BracketedWindow::colorDelegateFactory);
    addOutputType("match", "Only matches",
        &BracketedWindow::visibilityDelegateFactory);
    addOutputType("kwic",
        "Keyword in Context", &BracketedWindow::keywordInContextDelegateFactory);
}

void BracketedWindow::reloadListDelegate()
{
    listDelegateChanged(d_ui->listDelegateComboBox->currentIndex());
}

void BracketedWindow::progressStarted(int totalEntries)
{
    d_ui->filterProgressBar->setMinimum(0);
    d_ui->filterProgressBar->setMaximum(totalEntries);
    d_ui->filterProgressBar->setValue(0);
    d_ui->filterProgressBar->setVisible(true);
}

void BracketedWindow::progressChanged(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setValue(processedEntries);
}

void BracketedWindow::progressFinished(int processedEntries, int totalEntries, bool cached)
{
    progressStopped(processedEntries, totalEntries);
}

void BracketedWindow::progressStopped(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setVisible(false);
    emit saveStateChanged();
}

void BracketedWindow::closeEvent(QCloseEvent *event)
{
    writeSettings();
    event->accept();
}

void BracketedWindow::readSettings()
{
    QSettings settings;

    bool show = settings.value("bracketed_show_filenames", true).toBool();
    showFilenames(show);

    /*

    // restore last selected display method
    int delegateIndex = settings.value("filter_list_delegate", 0).toInt();
    listDelegateChanged(delegateIndex);
    d_ui->listDelegateComboBox->setCurrentIndex(delegateIndex);

    */

}

void BracketedWindow::writeSettings()
{
    QSettings settings;

    settings.setValue("bracketed_show_filenames", d_ui->filenamesCheckBox->isChecked());

    // display method
    settings.setValue("filter_list_delegate", d_ui->listDelegateComboBox->currentIndex());
}

void BracketedWindow::copy()
{
    QString output;
    QTextStream textstream(&output, QIODevice::WriteOnly | QIODevice::Text);

    selectionAsCSV(textstream);

    if (!output.isEmpty())
        QApplication::clipboard()->setText(output);
}

void BracketedWindow::exportSelection()
{
    QString filename(QFileDialog::getSaveFileName(this,
        "Export selection",
        QString(), "*.txt"));

    if (filename.isNull())
        return;

    QFile file(filename);

    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QMessageBox::critical(this,
            tr("Error exporting selection"),
            tr("Could open file for writing."),
            QMessageBox::Ok);

        return;
    }

    QTextStream textstream(&file);

    textstream.setGenerateByteOrderMark(true);
    selectionAsCSV(textstream);

    file.close();
}

void BracketedWindow::selectionAsCSV(QTextStream &output)
{
    // Nothing loaded? Do nothing.
    if (!d_model)
        return;

    QModelIndexList rows = d_ui->resultsTable->selectionModel()->selectedRows();

    // If there is nothing selected, do nothing
    if (rows.isEmpty())
        return;

    BracketedDelegate* delegate = dynamic_cast<BracketedDelegate*>(d_ui->resultsTable->itemDelegateForColumn(2));

    // Could not cast QAbstractItemDelegate to BracketedDelegate? Typical, but it is possible.
    if (!delegate)
        return;

    foreach (QModelIndex const &row, rows)
    {
        // This only works if the selection behavior is SelectRows
        output << delegate->sentenceForClipboard(row)
               << '\n';
    }

    output.flush();
}

QStyledItemDelegate* BracketedWindow::colorDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedColorDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::visibilityDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedVisibilityDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::keywordInContextDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedKeywordInContextDelegate(reader);
}

void BracketedWindow::saveAs()
{
    if (d_model.isNull())
        return;

    int nlines = d_model->rowCount(QModelIndex());

    if (nlines == 0)
        return;

    QString filename;
    QStringList filenames;

    QFileDialog::QFileDialog fd(this, tr("Save"), QString(), tr("Text (*.txt);;HTML (*.html *.htm)"));
    fd.setAcceptMode(QFileDialog::AcceptSave);
    fd.setConfirmOverwrite(true);
    fd.setLabelText(QFileDialog::Accept, tr("Save"));
    if (d_lastfilterchoice.size())
        fd.selectNameFilter(d_lastfilterchoice);
    if (fd.exec())
        filenames = fd.selectedFiles();
    else
        return;
    if (filenames.size() < 1)
        return;
    filename = filenames[0];
    if (! filename.length())
        return;

    OutputFormat format;
    d_lastfilterchoice = fd.selectedNameFilter();
    if (d_lastfilterchoice.contains("*.txt"))
        format = FormatText;
    else
        format = FormatHTML;

    QFile data(filename);
    if (!data.open(QFile::WriteOnly | QFile::Truncate)) {
        QMessageBox::critical(this,
                              tr("Save file error"),
                              tr("Cannot save file %1 (error code %2)").arg(filename).arg(data.error()),
                              QMessageBox::Ok);
        return;
    }

    QTextStream out(&data);
    out.setCodec("UTF-8");

    QString xmlEntries = d_model->asXML();

    QSharedPointer<QFile> stylesheet;

    if (format == FormatText)
        stylesheet = QSharedPointer<QFile>(new QFile(":/stylesheets/bracketed-text.xsl"));
    else
        stylesheet = QSharedPointer<QFile>(new QFile(":/stylesheets/bracketed-html.xsl"));

    XSLTransformer::ParamHash params;

    int idx = d_ui->listDelegateComboBox->currentIndex();
    int outputIdx = d_ui->listDelegateComboBox->itemData(idx, Qt::UserRole).toInt();
    params["outputType"] = QString("'%1'").arg(d_outputTypes[outputIdx]);

    if (d_ui->filenamesCheckBox->isChecked())
        params["showFilenames"] = "1";

    XSLTransformer trans(*stylesheet);
    out << trans.transform(xmlEntries, params);

    out.flush();
    data.close();

    emit statusMessage(tr("File saved as %1").arg(filename));

    /*
    QMessageBox::information(this,
                             tr("File saved"),
                             tr("File saved as %1").arg(filename),
                             QMessageBox::Ok);
    */
}

bool BracketedWindow::saveEnabled() const
{
    if (d_model.isNull())
        return false;
    if (d_model->rowCount(QModelIndex()) == 0)
        return false;

    return true;
}
<commit_msg>Do not show filenames by default.<commit_after>#include <QClipboard>
#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QHash>
#include <QKeyEvent>
#include <QLineEdit>
#include <QList>
#include <QMessageBox>
#include <QPoint>
#include <QSettings>
#include <QSize>
#include <QTextStream>
#include <QVector>
#include <XSLTransformer.hh>

#include <stdexcept>
#include <typeinfo>

#include "BracketedDelegate.hh"
#include "BracketedColorDelegate.hh"
#include "BracketedKeywordInContextDelegate.hh"
#include "BracketedVisibilityDelegate.hh"
#include "BracketedWindow.hh"
#include "CorpusWidget.hh"
#include "DactMacrosModel.hh"
#include "FilterModel.hh"
#include "Query.hh"
#include "ValidityColor.hh"
#include "ui_BracketedWindow.h"

namespace ac = alpinocorpus;

BracketedWindow::BracketedWindow(QWidget *parent) :
    CorpusWidget(parent),
    d_ui(QSharedPointer<Ui::BracketedWindow>(new Ui::BracketedWindow))
{
    d_ui->setupUi(this);

    initListDelegates();
    createActions();
    readSettings();
}

BracketedWindow::~BracketedWindow()
{
    writeSettings();
}

void BracketedWindow::cancelQuery()
{
    if (d_model)
        d_model->cancelQuery();
}

void BracketedWindow::colorChanged()
{
    reloadListDelegate();
}

void BracketedWindow::queryFailed(QString error)
{
    progressStopped(0, 0);

    QMessageBox::critical(this, tr("Error processing query"),
        tr("Could not process query: ") + error,
        QMessageBox::Ok);
}

void BracketedWindow::switchCorpus(QSharedPointer<ac::CorpusReader> corpusReader)
{
    d_corpusReader = corpusReader;
    emit saveStateChanged();
}

void BracketedWindow::setFilter(QString const &filter, QString const &raw_filter)
{
    Q_UNUSED(raw_filter);

    d_filter = filter;
    startQuery();
}

void BracketedWindow::setModel(FilterModel *model)
{
    d_model = QSharedPointer<FilterModel>(model);
    d_ui->resultsTable->setModel(d_model.data());

    emit saveStateChanged();

    //d_ui->resultsTable->setColumnHidden(1, true);

    //d_ui->resultsTable->horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents);
    //d_ui->resultsTable->horizontalHeader()->setResizeMode(1, QHeaderView::ResizeToContents);
    //d_ui->resultsTable->horizontalHeader()->setResizeMode(2, QHeaderView::ResizeToContents);

    d_ui->resultsTable->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    d_ui->resultsTable->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    d_ui->resultsTable->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);

    // disables horizontal jumping when a sentence is selected
    d_ui->resultsTable->setAutoScroll(false);

    /*
    connect(d_model.data(), SIGNAL(queryEntryFound(QString)),
        this, SLOT(updateResultsTotalCount()));
    */

    connect(d_model.data(), SIGNAL(queryFailed(QString)),
        SLOT(queryFailed(QString)));

    connect(d_model.data(), SIGNAL(queryStarted(int)),
        SLOT(progressStarted(int)));

    connect(d_model.data(), SIGNAL(queryStopped(int, int)),
        SLOT(progressStopped(int, int)));

    connect(d_model.data(), SIGNAL(queryFinished(int, int, bool)),
            SLOT(progressFinished(int, int, bool)));

}

void BracketedWindow::startQuery()
{
    // XXX - only once
    QFile file(":/stylesheets/bracketed-sentence-xml.xsl");
    file.open(QIODevice::ReadOnly);
    QTextStream xslStream(&file);
    QString stylesheet = xslStream.readAll();

    if (d_filter.trimmed().isEmpty())
        setModel(new FilterModel(QSharedPointer<ac::CorpusReader>()));
    else
        setModel(new FilterModel(d_corpusReader));

    // Reload the list delegate since they keep their results cached.
    // This will make sure no old cached data is used.
    reloadListDelegate();

    // This would be the correct manner to execute the query:
    //
    //d_model->runQuery(generateQuery(d_filter, "(@cat or @root)"),
    //  stylesheet);
    //
    // However, in some cases this will result in an insanely slow
    // query (#68). So, we now execute the query as-is, and in the
    // stylesheets only use the matching nodes that have a @cat or
    // @root attribute. Theoretically, this could lead to the addition
    // of sentences to the model where nothing is bracketed. If this
    // happens, this is the place to start looking.

    d_model->runQuery(d_filter, stylesheet);

    showFilenamesChanged();
}

void BracketedWindow::applyValidityColor(QString const &)
{
    ::applyValidityColor(sender());
}

void BracketedWindow::createActions()
{
    /*
    QObject::connect(d_ui->resultsListWidget,
        SIGNAL(currentItemChanged(QListWidgetItem *,QListWidgetItem *)),
        this,
        SLOT(entrySelected(QListWidgetItem*,QListWidgetItem*)));
    */

    QObject::connect(d_ui->resultsTable,
        // itemActivated is triggered by a single click on some systems
        // where this is the configured behavior: it can be annoying.
        // But it also enables using [enter] to raise the main window
        // which is the expected/preferred behavior.
        SIGNAL(activated(QModelIndex const &)),
        this,
        SLOT(entryActivated(QModelIndex const &)));

    QObject::connect(d_ui->listDelegateComboBox, SIGNAL(currentIndexChanged(int)),
        this, SLOT(listDelegateChanged(int)));

    connect(d_ui->filenamesCheckBox, SIGNAL(toggled(bool)),
        SLOT(showFilenamesChanged()));
}

void BracketedWindow::showFilenames(bool show)
{
   d_ui->resultsTable->setColumnHidden(0, !show);
   d_ui->resultsTable->setColumnHidden(1, !show);
   d_ui->filenamesCheckBox->setChecked(show);
}

void BracketedWindow::showFilenamesChanged()
{
    showFilenames(d_ui->filenamesCheckBox->isChecked());
}

/*
void BracketedWindow::entrySelected(QListWidgetItem *current, QListWidgetItem *)
{
    if (current == 0)
        return;

    emit currentEntryChanged(current->data(Qt::UserRole).toString());

    // Raises this window again when using cursor keys after using
    // [enter] to raise the main window.
    raise();
}
*/

void BracketedWindow::entryActivated(QModelIndex const &index)
{
    emit entryActivated(index.sibling(index.row(), 0).data(Qt::UserRole).toString());
}

void BracketedWindow::addOutputType(QString const &outputType,
    QString const &description, DelegateFactory factory)
{
    d_outputTypes.append(outputType);
    d_ui->listDelegateComboBox->addItem(description,
        d_listDelegateFactories.size());
    d_listDelegateFactories.append(factory);
}

void BracketedWindow::listDelegateChanged(int index)
{
    int delegateIndex = d_ui->listDelegateComboBox->itemData(index, Qt::UserRole).toInt();

    if (delegateIndex >= d_listDelegateFactories.size())
    {
        qWarning() << QString("Trying to select a list delegate (%1) beyond the boundary "
                              "of the d_listDelegateFactories list (%2)")
                             .arg(delegateIndex).arg(d_listDelegateFactories.size());
        return;
    }

    QAbstractItemDelegate* prevItemDelegate = d_ui->resultsTable->itemDelegateForColumn(2);
    d_ui->resultsTable->setItemDelegateForColumn(2, d_listDelegateFactories[delegateIndex](d_corpusReader));
    delete prevItemDelegate;
    d_ui->resultsTable->resizeRowsToContents();
}

void BracketedWindow::initListDelegates()
{
    addOutputType("sentence", "Complete sentence",
        &BracketedWindow::colorDelegateFactory);
    addOutputType("match", "Only matches",
        &BracketedWindow::visibilityDelegateFactory);
    addOutputType("kwic",
        "Keyword in Context", &BracketedWindow::keywordInContextDelegateFactory);
}

void BracketedWindow::reloadListDelegate()
{
    listDelegateChanged(d_ui->listDelegateComboBox->currentIndex());
}

void BracketedWindow::progressStarted(int totalEntries)
{
    d_ui->filterProgressBar->setMinimum(0);
    d_ui->filterProgressBar->setMaximum(totalEntries);
    d_ui->filterProgressBar->setValue(0);
    d_ui->filterProgressBar->setVisible(true);
}

void BracketedWindow::progressChanged(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setValue(processedEntries);
}

void BracketedWindow::progressFinished(int processedEntries, int totalEntries, bool cached)
{
    progressStopped(processedEntries, totalEntries);
}

void BracketedWindow::progressStopped(int processedEntries, int totalEntries)
{
    d_ui->filterProgressBar->setVisible(false);
    emit saveStateChanged();
}

void BracketedWindow::closeEvent(QCloseEvent *event)
{
    writeSettings();
    event->accept();
}

void BracketedWindow::readSettings()
{
    QSettings settings;

    bool show = settings.value("bracketed_show_filenames", false).toBool();
    showFilenames(show);

    /*

    // restore last selected display method
    int delegateIndex = settings.value("filter_list_delegate", 0).toInt();
    listDelegateChanged(delegateIndex);
    d_ui->listDelegateComboBox->setCurrentIndex(delegateIndex);

    */

}

void BracketedWindow::writeSettings()
{
    QSettings settings;

    settings.setValue("bracketed_show_filenames", d_ui->filenamesCheckBox->isChecked());

    // display method
    settings.setValue("filter_list_delegate", d_ui->listDelegateComboBox->currentIndex());
}

void BracketedWindow::copy()
{
    QString output;
    QTextStream textstream(&output, QIODevice::WriteOnly | QIODevice::Text);

    selectionAsCSV(textstream);

    if (!output.isEmpty())
        QApplication::clipboard()->setText(output);
}

void BracketedWindow::exportSelection()
{
    QString filename(QFileDialog::getSaveFileName(this,
        "Export selection",
        QString(), "*.txt"));

    if (filename.isNull())
        return;

    QFile file(filename);

    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QMessageBox::critical(this,
            tr("Error exporting selection"),
            tr("Could open file for writing."),
            QMessageBox::Ok);

        return;
    }

    QTextStream textstream(&file);

    textstream.setGenerateByteOrderMark(true);
    selectionAsCSV(textstream);

    file.close();
}

void BracketedWindow::selectionAsCSV(QTextStream &output)
{
    // Nothing loaded? Do nothing.
    if (!d_model)
        return;

    QModelIndexList rows = d_ui->resultsTable->selectionModel()->selectedRows();

    // If there is nothing selected, do nothing
    if (rows.isEmpty())
        return;

    BracketedDelegate* delegate = dynamic_cast<BracketedDelegate*>(d_ui->resultsTable->itemDelegateForColumn(2));

    // Could not cast QAbstractItemDelegate to BracketedDelegate? Typical, but it is possible.
    if (!delegate)
        return;

    foreach (QModelIndex const &row, rows)
    {
        // This only works if the selection behavior is SelectRows
        output << delegate->sentenceForClipboard(row)
               << '\n';
    }

    output.flush();
}

QStyledItemDelegate* BracketedWindow::colorDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedColorDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::visibilityDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedVisibilityDelegate(reader);
}

QStyledItemDelegate* BracketedWindow::keywordInContextDelegateFactory(CorpusReaderPtr reader)
{
    return new BracketedKeywordInContextDelegate(reader);
}

void BracketedWindow::saveAs()
{
    if (d_model.isNull())
        return;

    int nlines = d_model->rowCount(QModelIndex());

    if (nlines == 0)
        return;

    QString filename;
    QStringList filenames;

    QFileDialog::QFileDialog fd(this, tr("Save"), QString(), tr("Text (*.txt);;HTML (*.html *.htm)"));
    fd.setAcceptMode(QFileDialog::AcceptSave);
    fd.setConfirmOverwrite(true);
    fd.setLabelText(QFileDialog::Accept, tr("Save"));
    if (d_lastfilterchoice.size())
        fd.selectNameFilter(d_lastfilterchoice);
    if (fd.exec())
        filenames = fd.selectedFiles();
    else
        return;
    if (filenames.size() < 1)
        return;
    filename = filenames[0];
    if (! filename.length())
        return;

    OutputFormat format;
    d_lastfilterchoice = fd.selectedNameFilter();
    if (d_lastfilterchoice.contains("*.txt"))
        format = FormatText;
    else
        format = FormatHTML;

    QFile data(filename);
    if (!data.open(QFile::WriteOnly | QFile::Truncate)) {
        QMessageBox::critical(this,
                              tr("Save file error"),
                              tr("Cannot save file %1 (error code %2)").arg(filename).arg(data.error()),
                              QMessageBox::Ok);
        return;
    }

    QTextStream out(&data);
    out.setCodec("UTF-8");

    QString xmlEntries = d_model->asXML();

    QSharedPointer<QFile> stylesheet;

    if (format == FormatText)
        stylesheet = QSharedPointer<QFile>(new QFile(":/stylesheets/bracketed-text.xsl"));
    else
        stylesheet = QSharedPointer<QFile>(new QFile(":/stylesheets/bracketed-html.xsl"));

    XSLTransformer::ParamHash params;

    int idx = d_ui->listDelegateComboBox->currentIndex();
    int outputIdx = d_ui->listDelegateComboBox->itemData(idx, Qt::UserRole).toInt();
    params["outputType"] = QString("'%1'").arg(d_outputTypes[outputIdx]);

    if (d_ui->filenamesCheckBox->isChecked())
        params["showFilenames"] = "1";

    XSLTransformer trans(*stylesheet);
    out << trans.transform(xmlEntries, params);

    out.flush();
    data.close();

    emit statusMessage(tr("File saved as %1").arg(filename));

    /*
    QMessageBox::information(this,
                             tr("File saved"),
                             tr("File saved as %1").arg(filename),
                             QMessageBox::Ok);
    */
}

bool BracketedWindow::saveEnabled() const
{
    if (d_model.isNull())
        return false;
    if (d_model->rowCount(QModelIndex()) == 0)
        return false;

    return true;
}
<|endoftext|>


<commit_before>//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.

#include <cassert>
#include <vector>
#include <set>
#include <unordered_map>

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeBuilder.h"
#if LLVM_VERSION_MAJOR >= 4 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5)
  #include "llvm/IR/InstIterator.h"
#else
  #include "llvm/Support/InstIterator.h"
#endif
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <llvm/IR/DebugInfoMetadata.h>

using namespace llvm;

class DeleteUndefined : public ModulePass {
  Function *_vms = nullptr; // verifier_make_symbolic function
  Type *_size_t_Ty = nullptr; // type of size_t
  bool _nosym; // do not use symbolic values when replacing

  std::unordered_map<llvm::Type *, llvm::GlobalVariable *> added_globals;

  // add global of given type and initialize it in may as nondeterministic
  GlobalVariable *getGlobalNondet(llvm::Type *, llvm::Module *);
  Function *get_verifier_make_symbolic(llvm::Module *);
  Type *get_size_t(llvm::Module *);

  //void replaceCall(CallInst *CI, Module *M);
  void defineFunction(Module *M, Function *F);
protected:
  DeleteUndefined(char id) : ModulePass(id), _nosym(true) {}

public:
  static char ID;

  DeleteUndefined() : ModulePass(ID), _nosym(false) {}

  virtual bool runOnModule(Module& M) override;
  bool runOnFunction(Function &F);
};

static RegisterPass<DeleteUndefined> DLTU("delete-undefined",
                                          "delete calls to undefined functions, "
                                          "possible return value is made symbolic");
char DeleteUndefined::ID;

class DeleteUndefinedNoSym : public DeleteUndefined {
  public:
    static char ID;

    DeleteUndefinedNoSym() : DeleteUndefined(ID) {}
};

static RegisterPass<DeleteUndefinedNoSym> DLTUNS("delete-undefined-nosym",
                                          "delete calls to undefined functions, "
                                          "possible return value is made 0");
char DeleteUndefinedNoSym::ID;

static const char *leave_calls[] = {
  "__assert_fail",
  "abort",
  "klee_make_symbolic",
  "klee_assume",
  "klee_abort",
  "klee_silent_exit",
  "klee_report_error",
  "klee_warning_once",
  "klee_int",
  "exit",
  "_exit",
  "malloc",
  "calloc",
  "realloc",
  "free",
  "memset",
  "memcmp",
  "memcpy",
  "memmove",
  "kzalloc",
  "__errno_location",
  NULL
};

static bool array_match(const StringRef &name, const char **array)
{
  for (const char **curr = array; *curr; curr++)
    if (name.equals(*curr))
      return true;
  return false;
}

bool DeleteUndefined::runOnModule(Module& M) {
    M.materializeAll();

    // delete/replace the calls in the rest of functions
    bool modified = false;
    for (auto& F : M.getFunctionList()) {
      if (F.isIntrinsic())
        continue;

      modified |= runOnFunction(F);
    }

    return modified;
}

#if 0
/** Clone metadata from one instruction to another
 * @param i1 the first instruction
 * @param i2 the second instruction without any metadata
*/
static void CloneMetadata(const llvm::Instruction *i1, llvm::Instruction *i2)
{
    if (!i1->hasMetadata())
        return;

    assert(!i2->hasMetadata());
    llvm::SmallVector< std::pair< unsigned, llvm::MDNode * >, 2> mds;
    i1->getAllMetadata(mds);

    for (const auto& it : mds) {
        i2->setMetadata(it.first, it.second->clone().release());
    }
}
#endif

static void CallAddMetadata(CallInst *CI, Instruction *I)
{
  if (const DISubprogram *DS = I->getParent()->getParent()->getSubprogram()) {
    // no metadata? then it is going to be the instrumentation
    // of alloca or such at the beggining of function,
    // so just add debug loc of the beginning of the function
    CI->setDebugLoc(DebugLoc::get(DS->getLine(), 0, DS));
  }
}

Function *DeleteUndefined::get_verifier_make_symbolic(llvm::Module *M)
{
  if (_vms)
    return _vms;

  LLVMContext& Ctx = M->getContext();
  //void verifier_make_symbolic(void *addr, size_t nbytes, const char *name);
  Constant *C = M->getOrInsertFunction("__VERIFIER_make_symbolic",
                                       Type::getVoidTy(Ctx),
                                       Type::getInt8PtrTy(Ctx), // addr
                                       get_size_t(M),   // nbytes
                                       Type::getInt8PtrTy(Ctx), // name
                                       nullptr);
  _vms = cast<Function>(C);
  return _vms;
}

Type *DeleteUndefined::get_size_t(llvm::Module *M)
{
  if (_size_t_Ty)
    return _size_t_Ty;

  std::unique_ptr<DataLayout> DL
    = std::unique_ptr<DataLayout>(new DataLayout(M->getDataLayout()));
  LLVMContext& Ctx = M->getContext();

  if (DL->getPointerSizeInBits() > 32)
    _size_t_Ty = Type::getInt64Ty(Ctx);
  else
    _size_t_Ty = Type::getInt32Ty(Ctx);

  return _size_t_Ty;
}

// add global of given type and initialize it in may as nondeterministic
// FIXME: use the same variables as in InitializeUninitialized
GlobalVariable *DeleteUndefined::getGlobalNondet(llvm::Type *Ty, llvm::Module *M)
{
  auto it = added_globals.find(Ty);
  if (it != added_globals.end())
    return it->second;

  LLVMContext& Ctx = M->getContext();
  GlobalVariable *G = new GlobalVariable(*M, Ty, false /* constant */,
                                         GlobalValue::PrivateLinkage,
                                         /* initializer */
                                         Constant::getNullValue(Ty),
                                         "nondet_gl_undef");

  added_globals.emplace(Ty, G);

  // insert initialization of the new global variable
  // at the beginning of main
  Function *vms = get_verifier_make_symbolic(M);
  CastInst *CastI = CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Ctx));

  std::vector<Value *> args;
  //XXX: we should not build the new DL every time
  std::unique_ptr<DataLayout> DL
    = std::unique_ptr<DataLayout>(new DataLayout(M->getDataLayout()));

  args.push_back(CastI);
  args.push_back(ConstantInt::get(get_size_t(M), DL->getTypeAllocSize(Ty)));
  Constant *name = ConstantDataArray::getString(Ctx, "nondet");
  GlobalVariable *nameG = new GlobalVariable(*M, name->getType(), true /*constant */,
                                             GlobalVariable::PrivateLinkage, name);
  args.push_back(ConstantExpr::getPointerCast(nameG, Type::getInt8PtrTy(Ctx)));
  CallInst *CI = CallInst::Create(vms, args);

  Function *main = M->getFunction("main");
  assert(main && "Do not have main");
  BasicBlock& block = main->getBasicBlockList().front();
  // there must be some instruction, otherwise we would not be calling
  // this function
  Instruction& I = *(block.begin());
  CastI->insertBefore(&I);
  CI->insertBefore(&I);

  // add metadata due to the inliner pass
  CallAddMetadata(CI, &I);
  //CloneMetadata(&I, CastI);

  return G;
}

/*
void DeleteUndefined::replaceCall(CallInst *CI, Module *M)
{
  LLVMContext& Ctx = M->getContext();
  Type *Ty = CI->getType();
  // we checked for this before
  assert(!Ty->isVoidTy());
  // what to do in this case?
  assert(Ty->isSized());

  LoadInst *LI = new LoadInst(getGlobalNondet(Ty, M));
  LI->insertBefore(CI);
  CI->replaceAllUsesWith(LI);
}
*/

void DeleteUndefined::defineFunction(Module *M, Function *F)
{
  assert(F->size() == 0);
  assert(!F->getReturnType()->isVoidTy());

  LLVMContext& Ctx = M->getContext();
  BasicBlock *block = BasicBlock::Create(Ctx, "entry", F);
  if (_nosym) {
    // replace the return value with 0, since we don't want
    // to use the symbolic value
    ReturnInst::Create(Ctx, Constant::getNullValue(F->getReturnType()), block);
  } else {
    LoadInst *LI = new LoadInst(getGlobalNondet(F->getReturnType(), M),
                                "ret_from_undef", block);
    ReturnInst::Create(Ctx, LI, block);
  }

  F->setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
}

bool DeleteUndefined::runOnFunction(Function &F)
{
  // static set for the calls that we removed, so that
  // we can print those call only once
  static std::set<const llvm::Value *> removed_calls;
  Module *M = F.getParent();

  if (F.getName().startswith("__VERIFIER_"))
    return false;

  if (array_match(F.getName(), leave_calls))
    return false;

  if (F.empty() && !F.getReturnType()->isVoidTy()) {
    errs() << "Defining function " << F.getName() << " as symbolic\n";
    defineFunction(M, &F);
    return true;
  }

  // nothing to do here...
  if (F.empty())
    return false;

  // if the function is defined, just delete the calls to undefined
  // functions that does not return anything (if it does return anything,
  // it was/will be fixed in defineFunction()
  bool modified = false;
  for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E;) {
    Instruction *ins = &*I;
    ++I;
    if (CallInst *CI = dyn_cast<CallInst>(ins)) {
      if (CI->isInlineAsm())
        continue;

      Value *val = CI->getCalledValue()->stripPointerCasts();
      Function *callee = dyn_cast<Function>(val);
      // if this is intrinsic call or a call via a function pointer,
      // let it be
      // XXX: do we handle the function pointers correctly? What if there
      // is only a declaration of a function and it is taken to pointer
      // and then called? We do not define it in this case...
      if (!callee || callee->isIntrinsic())
        continue;

      // here we continue only with undefined function that return nothing,
      // becuase the functions that return something were/will be
      // defined in defineFunction()
      if (!callee->getReturnType()->isVoidTy())
        continue;

      assert(callee->hasName());
      StringRef name = callee->getName();

      // if this is __VERIFIER_* call, keep it
      if (name.startswith("__VERIFIER_"))
        continue;

      if (array_match(name, leave_calls))
        continue;

      if (callee->isDeclaration()) {
        if (removed_calls.insert(callee).second)
            errs() << "Removed calls to '" << name << "' (function is undefined)\n";

        // remove the call
        assert(CI->getType()->isVoidTy());
        CI->eraseFromParent();
        modified = true;
      }
    }
  }
  return modified;
}

<commit_msg>DeleteUndefined: handle MaterializeAll<commit_after>//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.

#include <cassert>
#include <vector>
#include <set>
#include <unordered_map>

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeBuilder.h"
#if LLVM_VERSION_MAJOR >= 4 || (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 5)
  #include "llvm/IR/InstIterator.h"
#else
  #include "llvm/Support/InstIterator.h"
#endif
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <llvm/IR/DebugInfoMetadata.h>

#if LLVM_VERSION_MAJOR >= 4
#include <llvm/Support/Error.h>
#endif

using namespace llvm;

class DeleteUndefined : public ModulePass {
  Function *_vms = nullptr; // verifier_make_symbolic function
  Type *_size_t_Ty = nullptr; // type of size_t
  bool _nosym; // do not use symbolic values when replacing

  std::unordered_map<llvm::Type *, llvm::GlobalVariable *> added_globals;

  // add global of given type and initialize it in may as nondeterministic
  GlobalVariable *getGlobalNondet(llvm::Type *, llvm::Module *);
  Function *get_verifier_make_symbolic(llvm::Module *);
  Type *get_size_t(llvm::Module *);

  //void replaceCall(CallInst *CI, Module *M);
  void defineFunction(Module *M, Function *F);
protected:
  DeleteUndefined(char id) : ModulePass(id), _nosym(true) {}

public:
  static char ID;

  DeleteUndefined() : ModulePass(ID), _nosym(false) {}

  virtual bool runOnModule(Module& M) override;
  bool runOnFunction(Function &F);
};

static RegisterPass<DeleteUndefined> DLTU("delete-undefined",
                                          "delete calls to undefined functions, "
                                          "possible return value is made symbolic");
char DeleteUndefined::ID;

class DeleteUndefinedNoSym : public DeleteUndefined {
  public:
    static char ID;

    DeleteUndefinedNoSym() : DeleteUndefined(ID) {}
};

static RegisterPass<DeleteUndefinedNoSym> DLTUNS("delete-undefined-nosym",
                                          "delete calls to undefined functions, "
                                          "possible return value is made 0");
char DeleteUndefinedNoSym::ID;

static const char *leave_calls[] = {
  "__assert_fail",
  "abort",
  "klee_make_symbolic",
  "klee_assume",
  "klee_abort",
  "klee_silent_exit",
  "klee_report_error",
  "klee_warning_once",
  "klee_int",
  "exit",
  "_exit",
  "malloc",
  "calloc",
  "realloc",
  "free",
  "memset",
  "memcmp",
  "memcpy",
  "memmove",
  "kzalloc",
  "__errno_location",
  NULL
};

static bool array_match(const StringRef &name, const char **array)
{
  for (const char **curr = array; *curr; curr++)
    if (name.equals(*curr))
      return true;
  return false;
}

bool DeleteUndefined::runOnModule(Module& M) {
#if LLVM_VERSION_MAJOR >= 4
    if (llvm::Error err = M.materializeAll()) {
	std::error_code ec = errorToErrorCode(std::move(err));
	llvm::errs() << __PRETTY_FUNCTION__ << ": cannot load module: " <<
		ec.message();
	return false;
    }
#else
    M.materializeAll();
#endif

    // delete/replace the calls in the rest of functions
    bool modified = false;
    for (auto& F : M.getFunctionList()) {
      if (F.isIntrinsic())
        continue;

      modified |= runOnFunction(F);
    }

    return modified;
}

#if 0
/** Clone metadata from one instruction to another
 * @param i1 the first instruction
 * @param i2 the second instruction without any metadata
*/
static void CloneMetadata(const llvm::Instruction *i1, llvm::Instruction *i2)
{
    if (!i1->hasMetadata())
        return;

    assert(!i2->hasMetadata());
    llvm::SmallVector< std::pair< unsigned, llvm::MDNode * >, 2> mds;
    i1->getAllMetadata(mds);

    for (const auto& it : mds) {
        i2->setMetadata(it.first, it.second->clone().release());
    }
}
#endif

static void CallAddMetadata(CallInst *CI, Instruction *I)
{
  if (const DISubprogram *DS = I->getParent()->getParent()->getSubprogram()) {
    // no metadata? then it is going to be the instrumentation
    // of alloca or such at the beggining of function,
    // so just add debug loc of the beginning of the function
    CI->setDebugLoc(DebugLoc::get(DS->getLine(), 0, DS));
  }
}

Function *DeleteUndefined::get_verifier_make_symbolic(llvm::Module *M)
{
  if (_vms)
    return _vms;

  LLVMContext& Ctx = M->getContext();
  //void verifier_make_symbolic(void *addr, size_t nbytes, const char *name);
  Constant *C = M->getOrInsertFunction("__VERIFIER_make_symbolic",
                                       Type::getVoidTy(Ctx),
                                       Type::getInt8PtrTy(Ctx), // addr
                                       get_size_t(M),   // nbytes
                                       Type::getInt8PtrTy(Ctx), // name
                                       nullptr);
  _vms = cast<Function>(C);
  return _vms;
}

Type *DeleteUndefined::get_size_t(llvm::Module *M)
{
  if (_size_t_Ty)
    return _size_t_Ty;

  std::unique_ptr<DataLayout> DL
    = std::unique_ptr<DataLayout>(new DataLayout(M->getDataLayout()));
  LLVMContext& Ctx = M->getContext();

  if (DL->getPointerSizeInBits() > 32)
    _size_t_Ty = Type::getInt64Ty(Ctx);
  else
    _size_t_Ty = Type::getInt32Ty(Ctx);

  return _size_t_Ty;
}

// add global of given type and initialize it in may as nondeterministic
// FIXME: use the same variables as in InitializeUninitialized
GlobalVariable *DeleteUndefined::getGlobalNondet(llvm::Type *Ty, llvm::Module *M)
{
  auto it = added_globals.find(Ty);
  if (it != added_globals.end())
    return it->second;

  LLVMContext& Ctx = M->getContext();
  GlobalVariable *G = new GlobalVariable(*M, Ty, false /* constant */,
                                         GlobalValue::PrivateLinkage,
                                         /* initializer */
                                         Constant::getNullValue(Ty),
                                         "nondet_gl_undef");

  added_globals.emplace(Ty, G);

  // insert initialization of the new global variable
  // at the beginning of main
  Function *vms = get_verifier_make_symbolic(M);
  CastInst *CastI = CastInst::CreatePointerCast(G, Type::getInt8PtrTy(Ctx));

  std::vector<Value *> args;
  //XXX: we should not build the new DL every time
  std::unique_ptr<DataLayout> DL
    = std::unique_ptr<DataLayout>(new DataLayout(M->getDataLayout()));

  args.push_back(CastI);
  args.push_back(ConstantInt::get(get_size_t(M), DL->getTypeAllocSize(Ty)));
  Constant *name = ConstantDataArray::getString(Ctx, "nondet");
  GlobalVariable *nameG = new GlobalVariable(*M, name->getType(), true /*constant */,
                                             GlobalVariable::PrivateLinkage, name);
  args.push_back(ConstantExpr::getPointerCast(nameG, Type::getInt8PtrTy(Ctx)));
  CallInst *CI = CallInst::Create(vms, args);

  Function *main = M->getFunction("main");
  assert(main && "Do not have main");
  BasicBlock& block = main->getBasicBlockList().front();
  // there must be some instruction, otherwise we would not be calling
  // this function
  Instruction& I = *(block.begin());
  CastI->insertBefore(&I);
  CI->insertBefore(&I);

  // add metadata due to the inliner pass
  CallAddMetadata(CI, &I);
  //CloneMetadata(&I, CastI);

  return G;
}

/*
void DeleteUndefined::replaceCall(CallInst *CI, Module *M)
{
  LLVMContext& Ctx = M->getContext();
  Type *Ty = CI->getType();
  // we checked for this before
  assert(!Ty->isVoidTy());
  // what to do in this case?
  assert(Ty->isSized());

  LoadInst *LI = new LoadInst(getGlobalNondet(Ty, M));
  LI->insertBefore(CI);
  CI->replaceAllUsesWith(LI);
}
*/

void DeleteUndefined::defineFunction(Module *M, Function *F)
{
  assert(F->size() == 0);
  assert(!F->getReturnType()->isVoidTy());

  LLVMContext& Ctx = M->getContext();
  BasicBlock *block = BasicBlock::Create(Ctx, "entry", F);
  if (_nosym) {
    // replace the return value with 0, since we don't want
    // to use the symbolic value
    ReturnInst::Create(Ctx, Constant::getNullValue(F->getReturnType()), block);
  } else {
    LoadInst *LI = new LoadInst(getGlobalNondet(F->getReturnType(), M),
                                "ret_from_undef", block);
    ReturnInst::Create(Ctx, LI, block);
  }

  F->setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
}

bool DeleteUndefined::runOnFunction(Function &F)
{
  // static set for the calls that we removed, so that
  // we can print those call only once
  static std::set<const llvm::Value *> removed_calls;
  Module *M = F.getParent();

  if (F.getName().startswith("__VERIFIER_"))
    return false;

  if (array_match(F.getName(), leave_calls))
    return false;

  if (F.empty() && !F.getReturnType()->isVoidTy()) {
    errs() << "Defining function " << F.getName() << " as symbolic\n";
    defineFunction(M, &F);
    return true;
  }

  // nothing to do here...
  if (F.empty())
    return false;

  // if the function is defined, just delete the calls to undefined
  // functions that does not return anything (if it does return anything,
  // it was/will be fixed in defineFunction()
  bool modified = false;
  for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E;) {
    Instruction *ins = &*I;
    ++I;
    if (CallInst *CI = dyn_cast<CallInst>(ins)) {
      if (CI->isInlineAsm())
        continue;

      Value *val = CI->getCalledValue()->stripPointerCasts();
      Function *callee = dyn_cast<Function>(val);
      // if this is intrinsic call or a call via a function pointer,
      // let it be
      // XXX: do we handle the function pointers correctly? What if there
      // is only a declaration of a function and it is taken to pointer
      // and then called? We do not define it in this case...
      if (!callee || callee->isIntrinsic())
        continue;

      // here we continue only with undefined function that return nothing,
      // becuase the functions that return something were/will be
      // defined in defineFunction()
      if (!callee->getReturnType()->isVoidTy())
        continue;

      assert(callee->hasName());
      StringRef name = callee->getName();

      // if this is __VERIFIER_* call, keep it
      if (name.startswith("__VERIFIER_"))
        continue;

      if (array_match(name, leave_calls))
        continue;

      if (callee->isDeclaration()) {
        if (removed_calls.insert(callee).second)
            errs() << "Removed calls to '" << name << "' (function is undefined)\n";

        // remove the call
        assert(CI->getType()->isVoidTy());
        CI->eraseFromParent();
        modified = true;
      }
    }
  }
  return modified;
}

<|endoftext|>