<commit_before>#include <iostream>
using std::cout; using std::cerr; using std::endl;
#include <tuple>

/*	conventions
		...TBD...
*/

using uint = unsigned int;

template<class T> struct TYPE { using type = T; };

template<class A, class B> using COMMON2 = typename std::common_type<A, B>::type;
template<class... Ts> struct common_;
template<class T> struct common_<T> : TYPE<T> {};
template<class F, class... Ns> struct common_<F, Ns...> : TYPE<COMMON2<F, typename common_<Ns...>::type> {};
template<class... Ts> using COMMON = typename common_<Ts...>::type;

enum ValueKind { sta, dyn, ref };

template<ValueKind K> struct VALUE_KIND {
	using value_flag = void;
	static const ValueKind kind = K;
	static const bool isStatic = (K == sta);
	static const bool isDynamic = !isStatic;
};
template<class T, ValueKind SD = dyn, T V = T()> struct VALUE;

template<class T, T V> struct VALUE<T, sta, V> : TYPE<T>, VALUE_KIND<sta> {
	static const T value = V;
	operator const T & () const { return value; }
};

template<class T, T V> struct VALUE<T, dyn, V> : TYPE<T>, VALUE_KIND<dyn> {
	T value;
	operator const T & () const { return value; }
	operator T & () { return value; }
	template<class U> T & operator=(const U & v) { return value = v; }
};

template<class T, T V> struct VALUE<T, ref, V> : TYPE<T>, VALUE_KIND<ref> {
	const T & value;
	operator const T & () const { return value; }
};

template<class T, T V> using STATIC = VALUE<T, sta, V>;
template<class T> using DYNAMIC = VALUE<T, dyn>;
template<class T> using REF = VALUE<T, ref>;

using YES = void*;
using NO = bool;

template<class T> using ZERO = STATIC<T, 0>;
template<class T> using ONE = STATIC<T, 1>;
using TRUE = STATIC<bool, true>;
using FALSE = STATIC<bool, false>;
template<class A, class B> using ADD = STATIC<COMMON<typename A::type, typename B::type>, A::value + B::value>;
template<class X> using INC = STATIC<typename X::type, 1 + X::value>;

struct NIL { using nil_tag = void; };

#define TYPEDEF_TEST(fName_, typeName_) \
	template<class T> struct fName_ ## _ : FALSE { \
		template<class U> static YES f(typename U::typeName_ *); \
		template<class U> static NO f(...); \
		static const bool value = (sizeof(YES) == sizeof(f<T>(0))); \
	}; \
	template<class T> constexpr bool fName_() { return fName_ ## _<T>::value; } \
	template<class T> constexpr bool fName_(const T &) { return fName_ ## _<T>::value; }

TYPEDEF_TEST(isNil, nil_tag)
TYPEDEF_TEST(isValue, value_tag)

template<class... Ts> struct TYPES { using types = TYPES<Ts...>; };
TYPEDEF_TEST(isTypes, types)
template<class H, class T> struct CONS_T;
template<class H, class... Ts> struct CONS_T<H, TYPES<Ts...>> : TYPES<H, Ts...> {};
template<class A, class B> struct CAT_T;
template<class... As, class... Bs> struct CAT_T<TYPES<As...>, TYPES<Bs...>> : TYPES<As..., Bs...> {};

template<class T, T... args> struct VALUES : TYPE<T> { using values = VALUES; };
TYPEDEF_TEST(isValues, values)
template<class X, X H, class T> struct CONS_V;
template<class X, X H, X... Vs> struct CONS_V<X, H, VALUES<X, Vs...>> : VALUES<X, H, Vs...> {};
template<class A, class B> struct CAT_V;
template<class X, X... As, X... Bs> struct CAT_V<VALUES<X, As...>, VALUES<X, Bs...>> {};

template<class T> constexpr bool isList() { return isValues<T>() || isTypes<T>(); }

//#define MAYBE_TYPE(P_, T_) typename std::enable_if<P_<T>(), T>::type
template<bool C, class T, class F> struct COND : TYPE<T> {};
template<class T, class F> struct COND<false, T, F> : TYPE<F> {};

template<class T> struct LEN;
template<> struct LEN<TYPES<>> : ZERO<uint> {};
template<class T> struct LEN<VALUES<T>> : ZERO<uint> {};
template<class F, class... Ns> struct LEN<TYPES<F, Ns...>> : INC<LEN<TYPES<Ns...>>> {};
template<class T, T F, T... Ns> struct LEN<VALUES<T, F, Ns...>> : INC<LEN<VALUES<T, Ns...>>> {};
template<class T> constexpr typename std::enable_if<isList<T>(), uint>::type count() { return LEN<T>::value; }
template<class T> constexpr typename std::enable_if<isList<T>(), uint>::type count(const T &) { return LEN<T>::value; }

template<class T, template<class> class P> struct COUNT_T;
template<template<class> class P> struct COUNT_T<TYPES<>, P> : ZERO<uint> {};
template<template<class> class P, class F, class... Ns>  struct COUNT_T<TYPES<F, Ns...>, P> : STATIC<uint, (P<F>::value ? 1:0) + COUNT_T<TYPES<Ns...>, P>::value> {};
template<class T, template<class> class P> constexpr typename std::enable_if<isList<T>(), uint>::type count() { return COUNT_T<T, P>::value; }
template<class T, template<class> class P> constexpr typename std::enable_if<isList<T>(), uint>::type count(const T &) { return COUNT_T<T, P>::value; }

template<class T, template<typename T::type> class P> struct COUNT_V;
template<class T, template<T> class P> struct COUNT_V<VALUES<T>, P> : ZERO<uint> {};
template<class T, template<T> class P, T F, T... Ns> struct COUNT_V<VALUES<T, F, Ns...>, P> : STATIC<uint, (P<F>::value ? 1:0) + COUNT_V<VALUES<T, Ns...>, P>::value> {};
template<class T, template<typename T::type> class P> constexpr typename std::enable_if<isList<T>(), uint>::type count() { return COUNT_V<T, P>::value; }
template<class T, template<typename T::type> class P> constexpr typename std::enable_if<isList<T>(), uint>::type count(const T &) { return COUNT_V<T, P>::value; }

template<class T, template<class> class P> struct FILTER_T;
template<template<class> class P> struct FILTER_T<TYPES<>, P> : TYPES<> {};
template<template<class> class P, class F, class... Ns> struct FILTER_T<TYPES<F, Ns...>, P> : COND<
	P<F>::value,
	typename CONS_T< F, typename FILTER_T<TYPES<Ns...>, P>::types >::type,
	typename FILTER_T<TYPES<Ns...>, P >::types
>::type::types {};

template<class T, template<typename T::type> class P> struct FILTER_V;
template<class T, template<T> class P> struct FILTER_V<VALUES<T>, P> : VALUES<T> {};
template<class T, template<T> class P, T F, T... Vs> struct FILTER_V<VALUES<T, F, Vs...>, P> : COND<
	P<F>::value,
	typename CONS_V< T, F, typename FILTER_V<VALUES<T, Vs...>, P>::values >::type,
	typename FILTER_V<VALUES<T, Vs...>, P>::values
>::type::values {};

template<class T, template<class> class P> struct MAP_TT;
template<template<class> class P, class... Ts> struct MAP_TT<TYPES<Ts...>, P> : TYPES< typename P<Ts>::type... > {};

template<class T, template<class> class P> struct MAP_TV;
template<template<class> class P, class... Ts> struct MAP_TV<TYPES<Ts...>, P> : VALUES< typename P<void>::type, P<Ts>::value... > {};

template<class T, template<typename T::type> class P> struct MAP_VT;
template<class T, template<typename T::type> class P, T... Vs> struct MAP_VT<VALUES<T, Vs...>, P> : TYPES< typename P<Vs>::type... > {};

template<class T, template<typename T::type> class P> struct MAP_VV;
template<class T, template<typename T::type> class P, T... Vs> struct MAP_VV<VALUES<T, Vs...>, P> : VALUES< typename P<std::declval<T>()>::type, P<Vs>::value... > {};

template<class T, ValueKind SD, T V> std::ostream & operator<<(std::ostream & s, const VALUE<T, SD, V> & val) {
	if(SD == sta) s << '$';
	return s << val.value;
}

template<int... args> using ints_t = std::tuple< VALUE<uint, args < 0 ? dyn : sta, args < 0 ? 0 : args>... >;

template<int I, int N> struct tuple_ostream {
	template<class... Ts> static void f(std::ostream & s, const std::tuple<Ts...> & tp) {
		if(I) s << ", ";
		s << std::get<I>(tp);
		tuple_ostream<I+1, N>::f(s, tp);
	}
};
template<int N> struct tuple_ostream<N,N> {
	template<class... Ts> static void f(std::ostream &, const std::tuple<Ts...> &) {}
};
template<class... Ts> std::ostream & operator<<(std::ostream & s, const std::tuple<Ts...> & tp) {
	s << "tuple(";
	tuple_ostream<0, count<TYPES<Ts...>>()>::f(s, tp);
	return s << ')';
}

template<class T> struct positive {
	template<T x> using pred = STATIC<bool, x >= 0>;
};
template<class T> struct negative {
	template<T x> using pred = STATIC<bool, x < 0>;
};

template<int... args_> struct ints {
	using args = VALUES<int, args...>;
	static const uint n = count<VALUES<int, args_...>>();
	static const uint n_static = count<VALUES<int, args_...>, positive<int>::pred>(), n_dynamic = n - n_static;
	using dyn = typename MAP_VV<VALUES<int, args_...>, negative<int>::pred>::values;
	using index = typename CUMSUM<dyn>::values;
	uint data[n_dynamic];

	template<int i> int read() const {
		return AT<dyn, i>::value ? data[AT<index, i>::value] : AT<args, i>::value;
	}
	q
};

int main() {
	ints_t<-1, 1, 2, -1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15> vt;
	std::get<3>(vt) = 3;
	cout << sizeof(vt) << endl;
	cout << vt << endl;

	ints<-1, 1, 2, -1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15> v;
	cout << sizeof(v) << endl;
	cout << v << endl;
	return 0;
}
<commit_msg>fixed/added metafunctions<commit_after>#include <iostream>
using std::cout; using std::cerr; using std::endl;
#include <tuple>

/*	conventions

		lowercase or CamelCase	first-class object
		UPPERCASE				type which *inderectly* represents a first-class object

			using X = STATIC<int, 3>
				X represents 3 (X::value). Indirection => uppercase

			static const int x = 3;
				x is directly 3 => No indirection, lowercase

			using T = MAKE_CONST<int>
				T represents const int (T::type). Indirection => uppercase

			using T = make_cast<int>
				T is an alias to const int. No indirection => lowercase

			struct EMPTY {}
				EMPTY is used as a tag, to represent an empty set. The empty set is not even readable, only a convention => uppercase
*/

using uint = unsigned int;

template<class T> struct TYPE { using type = T; };

template<class A, class B> using common2_tt = typename std::common_type<A, B>::type;
template<class... Ts> struct COMMON;
template<class T> struct COMMON<T> : TYPE<T> {};
template<class F, class... Ns> struct COMMON<F, Ns...> : std::common_type<F, typename COMMON<Ns...>::type> {};
template<class... Ts> using common_tt = typename COMMON<Ts...>::type;

enum ValueKind { sta, dyn, ref };

template<ValueKind K> struct VALUE_KIND {
	using value_flag = void;
	static const ValueKind kind = K;
	static const bool isStatic = (K == sta);
	static const bool isDynamic = !isStatic;
};
template<class T, ValueKind SD = dyn, T V = T()> struct VALUE;

template<class T, T V> struct VALUE<T, sta, V> : TYPE<T>, VALUE_KIND<sta> {
	static const T value = V;
	operator const T & () const { return value; }
};

template<class T, T V> struct VALUE<T, dyn, V> : TYPE<T>, VALUE_KIND<dyn> {
	T value;
	operator const T & () const { return value; }
	operator T & () { return value; }
	template<class U> T & operator=(const U & v) { return value = v; }
};

template<class T, T V> struct VALUE<T, ref, V> : TYPE<T>, VALUE_KIND<ref> {
	const T & value;
	operator const T & () const { return value; }
};

template<class T, T V> using STATIC = VALUE<T, sta, V>;
template<class T> using DYNAMIC = VALUE<T, dyn>;
template<class T> using REF = VALUE<T, ref>;

using YES = void*;
using NO = bool;

template<class T> using ZERO = STATIC<T, 0>;
template<class T> using ONE = STATIC<T, 1>;
using TRUE = STATIC<bool, true>;
using FALSE = STATIC<bool, false>;
template<class A, class B> using ADD = STATIC<COMMON<typename A::type, typename B::type>, A::value + B::value>;
template<class X> using INC = STATIC<typename X::type, 1 + X::value>;

struct NIL { using nil_tag = void; };

#define TYPEDEF_TEST(fName_, typeName_) \
	template<class T> struct fName_ ## _ : FALSE { \
		template<class U> static YES f(typename U::typeName_ *); \
		template<class U> static NO f(...); \
		static const bool value = (sizeof(YES) == sizeof(f<T>(0))); \
	}; \
	template<class T> constexpr bool fName_() { return fName_ ## _<T>::value; } \
	template<class T> constexpr bool fName_(const T &) { return fName_ ## _<T>::value; }

TYPEDEF_TEST(isNil, nil_tag)
TYPEDEF_TEST(isValue, value_tag)

template<class... Ts> struct TYPES { using types = TYPES<Ts...>; };
TYPEDEF_TEST(isTypes, types)

template<class H, class T> struct CONS_T;
template<class H, class... Ts> struct CONS_T<H, TYPES<Ts...>> : TYPES<H, Ts...> {};
template<class H, class T> using cons_t = typename CONS_T<H, T>::types;

template<class A, class B> struct CAT_T;
template<class... As, class... Bs> struct CAT_T<TYPES<As...>, TYPES<Bs...>> : TYPES<As..., Bs...> {};
template<class A, class B> using cat_t = typename CAT_T<A, B>::types;

template<class T, T... args> struct VALUES : TYPE<T> { using values = VALUES; };
TYPEDEF_TEST(isValues, values)

template<class X, X H, class T> struct CONS_V;
template<class X, X H, X... Vs> struct CONS_V<X, H, VALUES<X, Vs...>> : VALUES<X, H, Vs...> {};
template<class X, X H, class T> using cons_v = typename CONS_V<X, H, T>::values;

template<class A, class B> struct CAT_V;
template<class X, X... As, X... Bs> struct CAT_V<VALUES<X, As...>, VALUES<X, Bs...>> {};
template<class A, class B> using cat_v = typename CAT_V<A, B>::values;

template<class T> constexpr bool isList() { return isValues<T>() || isTypes<T>(); }

//#define MAYBE_TYPE(P_, T_) typename std::enable_if<P_<T>(), T>::type
template<bool C, class T, class F> struct COND : TYPE<T> {};
template<class T, class F> struct COND<false, T, F> : TYPE<F> {};
template<bool C, class T, class F> using cond = typename COND<C, T, F>::type;

template<class T> struct LEN;
template<> struct LEN<TYPES<>> : ZERO<uint> {};
template<class T> struct LEN<VALUES<T>> : ZERO<uint> {};
template<class F, class... Ns> struct LEN<TYPES<F, Ns...>> : INC<LEN<TYPES<Ns...>>> {};
template<class T, T F, T... Ns> struct LEN<VALUES<T, F, Ns...>> : INC<LEN<VALUES<T, Ns...>>> {};
template<class T> constexpr typename std::enable_if<isList<T>(), uint>::type len() { return LEN<T>::value; }

template<class T, template<class> class P> struct COUNT_T;
template<template<class> class P> struct COUNT_T<TYPES<>, P> : ZERO<uint> {};
template<template<class> class P, class F, class... Ns>  struct COUNT_T<TYPES<F, Ns...>, P> : STATIC<uint, (P<F>::value ? 1:0) + COUNT_T<TYPES<Ns...>, P>::value> {};
template<class T, template<class> class P> constexpr typename std::enable_if<isList<T>(), uint>::type count() { return COUNT_T<T, P>::value; }

template<class T, template<typename T::type> class P> struct COUNT_V;
template<class T, template<T> class P> struct COUNT_V<VALUES<T>, P> : ZERO<uint> {};
template<class T, template<T> class P, T F, T... Ns> struct COUNT_V<VALUES<T, F, Ns...>, P> : STATIC<uint, (P<F>::value ? 1:0) + COUNT_V<VALUES<T, Ns...>, P>::value> {};
template<class T, template<typename T::type> class P> constexpr typename std::enable_if<isList<T>(), uint>::type count() { return COUNT_V<T, P>::value; }

template<class T, template<class> class P> struct FILTER_T;
template<template<class> class P> struct FILTER_T<TYPES<>, P> : TYPES<> {};
template<template<class> class P, class F, class... Ns> struct FILTER_T<TYPES<F, Ns...>, P> : COND<
	P<F>::value,
	typename CONS_T< F, typename FILTER_T<TYPES<Ns...>, P>::types >::type,
	typename FILTER_T<TYPES<Ns...>, P >::types
>::type::types {};
template<class T, template<class> class P> using filter_t = typename FILTER_T<T, P>::types;

template<class T, template<typename T::type> class P> struct FILTER_V;
template<class T, template<T> class P> struct FILTER_V<VALUES<T>, P> : VALUES<T> {};
template<class T, template<T> class P, T F, T... Vs> struct FILTER_V<VALUES<T, F, Vs...>, P> : COND<
	P<F>::value,
	typename CONS_V< T, F, typename FILTER_V<VALUES<T, Vs...>, P>::values >::type,
	typename FILTER_V<VALUES<T, Vs...>, P>::values
>::type::values {};
template<class T, template<typename T::type> class P> using filter_v = typename FILTER_V<T, P>::values;

template<class T, template<class> class P> struct MAP_TT;
template<template<class> class P, class... Ts> struct MAP_TT<TYPES<Ts...>, P> : TYPES< typename P<Ts>::type... > {};
template<class T, template<class> class P> using map_tt = typename MAP_TT<T, P>::types;

template<class T, template<class> class P> struct MAP_TV;
template<template<class> class P, class... Ts> struct MAP_TV<TYPES<Ts...>, P> : VALUES< typename P<void>::type, P<Ts>::value... > {};
template<class T, template<class> class P> using map_tv = typename MAP_TV<T, P>::values;

template<class T, template<typename T::type> class P> struct MAP_VT;
template<class T, template<typename T::type> class P, T... Vs> struct MAP_VT<VALUES<T, Vs...>, P> : TYPES< typename P<Vs>::type... > {};
template<class T, template<typename T::type> class P> using map_vt = typename MAP_VT<T, P>::types;

template<class T, template<typename T::type> class P> struct MAP_VV;
template<class T, template<typename T::type> class P, T... Vs> struct MAP_VV<VALUES<T, Vs...>, P> : VALUES< typename P<std::declval<T>()>::type, P<Vs>::value... > {};
template<class T, template<typename T::type> class P> using map_vv = typename MAP_VV<T, P>::values;

template<class T, template<class,class> class B, class S = void> struct REDUCE_TT;
template<template<class,class> class B, class S> struct REDUCE_TT<TYPES<>, B, S> : TYPE<S> {};
template<template<class,class> class B, class S, class F, class... Ns> struct REDUCE_TT<TYPES<F, Ns...>, B, S> : B<F, typename REDUCE_TT<TYPES<Ns...>, B, S>::type> {};
template<class T, template<class,class> class B, class S = void> using reduce_tt = typename REDUCE_TT<T, B, S>::type;

template<class T, template<typename T::type, typename T::type> class B, typename T::type S = typename T::type()> struct REDUCE_VV;
template<class T, template<T,T> class B, T S> struct REDUCE_VV<VALUES<T>, B, S> : VALUE<T,S> {};
template<class T, template<T,T> class B, T S, T F, T... Ns> struct REDUCE_VV<VALUES<T, F, Ns...>, B, S> : B<F, REDUCE_VV<VALUES<T, Ns...>, B, S>::value> {};
template<class T, template<typename T::type, typename T::type> class B, typename T::type S = typename T::type()> constexpr typename T::type reduce_vv() { return REDUCE_VV<T, B, S>::value; }

template<class T, ValueKind SD, T V> std::ostream & operator<<(std::ostream & s, const VALUE<T, SD, V> & val) {
	if(SD == sta) s << '$';
	return s << val.value;
}

template<int... args> using ints_t = std::tuple< VALUE<uint, args < 0 ? dyn : sta, args < 0 ? 0 : args>... >;

template<int I, int N> struct tuple_ostream {
	template<class... Ts> static void f(std::ostream & s, const std::tuple<Ts...> & tp) {
		if(I) s << ", ";
		s << std::get<I>(tp);
		tuple_ostream<I+1, N>::f(s, tp);
	}
};
template<int N> struct tuple_ostream<N,N> {
	template<class... Ts> static void f(std::ostream &, const std::tuple<Ts...> &) {}
};
template<class... Ts> std::ostream & operator<<(std::ostream & s, const std::tuple<Ts...> & tp) {
	s << "tuple(";
	tuple_ostream<0, count<TYPES<Ts...>>()>::f(s, tp);
	return s << ')';
}

template<class T> struct POSITIVE {
	template<T x> using pred = STATIC<bool, (x >= 0)>;
};
template<class T> struct NEGATIVE {
	template<T x> using pred = STATIC<bool, (x < 0)>;
};
template<class T> struct SUM {
	template<T a, T b> using bin = STATIC<T, a+b>;
};

template<int... args_> struct ints {
	using args = VALUES<int, args_...>;
	static const uint n = count<VALUES<int, args_...>>();
	static const uint n_static = count<VALUES<int, args_...>, POSITIVE<int>::pred>(), n_dynamic = n - n_static;
	using dyn = typename MAP_VV<VALUES<int, args_...>, NEGATIVE<int>::pred>::values;
	using index = typename CUMSUM<dyn>::values;
	uint data[n_dynamic];

	template<int i> int read() const {
		return AT<dyn, i>::value ? data[AT<index, i>::value] : AT<args, i>::value;
	}
	q
};

int main() {
	ints_t<-1, 1, 2, -1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15> vt;
	std::get<3>(vt) = 3;
	cout << sizeof(vt) << endl;
	cout << vt << endl;

	ints<-1, 1, 2, -1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15> v;
	cout << sizeof(v) << endl;
	cout << v << endl;
	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013  Daniel Vrátil <dvratil@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "widget.h"
#include "controlpanel.h"

#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeEngine>

#include <QtGui/QVBoxLayout>
#include <QtGui/QSplitter>
#include <QtGui/QLabel>
#include <QtCore/qglobal.h>

#include "declarative/qmloutput.h"
#include "declarative/qmlscreen.h"
#include "declarative/iconbutton.h"
#include "utils.h"

#include <kscreen/output.h>
#include <kscreen/edid.h>
#include <kscreen/mode.h>
#include <kscreen/config.h>
#include <QtCore/QDir>
#include <KLocalizedString>
#include <KComboBox>
#include <KPushButton>
#include <KDebug>

Widget::Widget(QWidget *parent):
    QWidget(parent),
    mScreen(0),
    mPrevConfig(0)
{
    QVBoxLayout *layout = new QVBoxLayout(this);

    QSplitter *splitter = new QSplitter(Qt::Vertical, this);
    layout->addWidget(splitter);

    m_declarativeView = new QDeclarativeView(this);
    m_declarativeView->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    splitter->addWidget(m_declarativeView);
    splitter->setStretchFactor(0, 1);
    loadQml();

    QWidget *widget = new QWidget(this);
    splitter->addWidget(widget);

    QHBoxLayout *hbox = new QHBoxLayout(widget);
    widget->setLayout(hbox);

    mPrimaryCombo = new KComboBox(this);
    mPrimaryCombo->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents);
    connect(mPrimaryCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotPrimaryChanged(int)));

    hbox->addWidget(new QLabel(i18n("Primary display:")));
    hbox->addWidget(mPrimaryCombo);

    hbox->addStretch();

    mProfilesCombo = new KComboBox(this);
    mProfilesCombo->addItem(i18n("Default Profile:"));
    mProfilesCombo->setEnabled(false);
    hbox->addWidget(new QLabel(i18n("Active profile")));
    hbox->addWidget(mProfilesCombo);

    m_controlPanel = new ControlPanel(this);
    m_controlPanel->setConfig(mConfig);
    connect(m_controlPanel, SIGNAL(changed()), this, SIGNAL(changed()));
    Q_FOREACH (KScreen::Output *output, mConfig->outputs()) {
        connect(output, SIGNAL(isConnectedChanged()), this, SLOT(slotOutputConnectedChanged()));
        connect(output, SIGNAL(isEnabledChanged()), this, SLOT(slotOutputEnabledChanged()));
        connect(output, SIGNAL(isPrimaryChanged()), this, SLOT(slotOutputPrimaryChanged()));

        if (!output->isConnected() || !output->isEnabled()) {
            continue;
        }

        mPrimaryCombo->addItem(Utils::outputName(output), output->id());
        if (output->isPrimary()) {
            mPrimaryCombo->setCurrentIndex(mPrimaryCombo->count() - 1);
        }
    }
    layout->addWidget(m_controlPanel);

    mUnifyButton = new KPushButton(i18n("Unify outputs"), this);
    connect(mUnifyButton, SIGNAL(clicked(bool)), this, SLOT(slotUnifyOutputs()));
    layout->addWidget(mUnifyButton);
}

Widget::~Widget()
{
}

KScreen::Config *Widget::currentConfig() const
{
    return mConfig;
}

void Widget::loadQml()
{
    qmlRegisterType<QMLOutput>("org.kde.kscreen", 1, 0, "QMLOutput");
    qmlRegisterType<QMLScreen>("org.kde.kscreen", 1, 0, "QMLScreen");
    qmlRegisterType<IconButton>("org.kde.kscreen", 1, 0, "IconButton");

    qmlRegisterType<KScreen::Output>("org.kde.kscreen", 1, 0, "KScreenOutput");
    qmlRegisterType<KScreen::Edid>("org.kde.kscreen", 1, 0, "KScreenEdid");
    qmlRegisterType<KScreen::Mode>("org.kde.kscreen", 1, 0, "KScreenMode");

    QDir dir = QDir::current();
    dir.cdUp();
    dir.cdUp();
    dir.cd("kcm/qml");
    QDir::setCurrent(dir.path());

    const QString file = QDir::currentPath() + "/main.qml";
    m_declarativeView->engine()->addImportPath(QLatin1String("/usr/lib64/kde4/imports/"));
    m_declarativeView->setSource(QUrl::fromLocalFile(file));

    QGraphicsObject *rootObject = m_declarativeView->rootObject();
    mScreen = rootObject->findChild<QMLScreen*>(QLatin1String("outputView"));
    if (!mScreen) {
        return;
    }

    connect(mScreen, SIGNAL(focusedOutputChanged(QMLOutput*)),
            this, SLOT(slotFocusedOutputChanged(QMLOutput*)));
    connect(mScreen, SIGNAL(focusedOutputChanged(QMLOutput*)),
            this, SIGNAL(changed()));

    mConfig = KScreen::Config::current();
    mScreen->setConfig(mConfig);
}

void Widget::slotFocusedOutputChanged(QMLOutput *output)
{
    m_controlPanel->activateOutput(output->output());
}

void Widget::slotOutputPrimaryChanged()
{
    const int id = qobject_cast<KScreen::Output*>(sender())->id();
    const int index = mPrimaryCombo->findData(id);
    mPrimaryCombo->blockSignals(true);
    mPrimaryCombo->setCurrentIndex(index);
    mPrimaryCombo->blockSignals(false);
}

void Widget::slotPrimaryChanged(int index)
{
    const int id = mPrimaryCombo->itemData(index).toInt();
    Q_FOREACH (KScreen::Output *output, mConfig->outputs()) {
        output->blockSignals(true);
        output->setPrimary(output->id() == id);
        output->blockSignals(false);
    }

    Q_EMIT changed();
}

void Widget::slotOutputConnectedChanged()
{
    KScreen::Output *output = qobject_cast<KScreen::Output*>(sender());
    if (output->isConnected()) {
        mPrimaryCombo->addItem(Utils::outputName(output), output->id());
        if (output->isPrimary()) {
            mPrimaryCombo->setCurrentIndex(mPrimaryCombo->count() - 1);
        }
    } else {
        const int index = mPrimaryCombo->findData(output->id());
        mPrimaryCombo->removeItem(index);
    }
}

void Widget::slotOutputEnabledChanged()
{
    int enabledOutputsCnt = 0;
    Q_FOREACH (KScreen::Output *output, mConfig->outputs()) {
        if (output->isEnabled()) {
            ++enabledOutputsCnt;
        }

        if (enabledOutputsCnt > 1) {
            break;
        }
    }

    KScreen::Output *output = qobject_cast<KScreen::Output*>(sender());
    if (output->isEnabled()) {
        mPrimaryCombo->addItem(Utils::outputName(output), output->id());
    } else {
        const int index = mPrimaryCombo->findData(output->id());
        mPrimaryCombo->removeItem(index);
    }

    mUnifyButton->setEnabled(enabledOutputsCnt > 1);
}

void Widget::slotUnifyOutputs()
{
    QMLOutput *base = mScreen->primaryOutput();
    QList<int> clones;

    if (base->isCloneMode()) {
        mScreen->setConfig(mPrevConfig);
        mConfig = mScreen->config();
        m_controlPanel->setConfig(mConfig);

        mPrimaryCombo->setEnabled(true);

        mUnifyButton->setText(i18n("Unify Outputs"));
    } else {
        // Clone the current config, so that we can restore it in case user
        // breaks the cloning
        mPrevConfig = mConfig->clone();

        Q_FOREACH (QMLOutput *output, mScreen->outputs()) {
            if (!output->output()->isConnected()) {
                continue;
            }

            if (!output->output()->isEnabled()) {
                output->hide();
                continue;
            }

            if (base == 0) {
                base = output;
            }

            output->setOutputX(0);
            output->setOutputY(0);
            output->output()->setPos(QPoint(0, 0));
            output->output()->setClones(QList<int>());

            if (base != output) {
                clones << output->output()->id();
                output->setCloneOf(base);
                output->hide();
            }
        }

        base->output()->setClones(clones);
        base->setIsCloneMode(true);

        mScreen->updateOutputsPlacement();

        mPrimaryCombo->setEnabled(false);
        m_controlPanel->setUnifiedOutput(base->output());

        mUnifyButton->setText(i18n("Break unified outputs"));
    }

    Q_EMIT changed();
}

#include "widget.moc"
<commit_msg>Properly handle configuration without primary output<commit_after>/*
 * Copyright (C) 2013  Daniel Vrátil <dvratil@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "widget.h"
#include "controlpanel.h"

#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeEngine>

#include <QtGui/QVBoxLayout>
#include <QtGui/QSplitter>
#include <QtGui/QLabel>
#include <QtCore/qglobal.h>

#include "declarative/qmloutput.h"
#include "declarative/qmlscreen.h"
#include "declarative/iconbutton.h"
#include "utils.h"

#include <kscreen/output.h>
#include <kscreen/edid.h>
#include <kscreen/mode.h>
#include <kscreen/config.h>
#include <QtCore/QDir>
#include <KLocalizedString>
#include <KComboBox>
#include <KPushButton>
#include <KDebug>

Widget::Widget(QWidget *parent):
    QWidget(parent),
    mScreen(0),
    mPrevConfig(0)
{
    QVBoxLayout *layout = new QVBoxLayout(this);

    QSplitter *splitter = new QSplitter(Qt::Vertical, this);
    layout->addWidget(splitter);

    m_declarativeView = new QDeclarativeView(this);
    m_declarativeView->setResizeMode(QDeclarativeView::SizeRootObjectToView);
    splitter->addWidget(m_declarativeView);
    splitter->setStretchFactor(0, 1);
    loadQml();

    QWidget *widget = new QWidget(this);
    splitter->addWidget(widget);

    QHBoxLayout *hbox = new QHBoxLayout(widget);
    widget->setLayout(hbox);

    mPrimaryCombo = new KComboBox(this);
    mPrimaryCombo->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents);
    mPrimaryCombo->addItem(i18n("No primary screen"));
    connect(mPrimaryCombo, SIGNAL(currentIndexChanged(int)), SLOT(slotPrimaryChanged(int)));

    hbox->addWidget(new QLabel(i18n("Primary display:")));
    hbox->addWidget(mPrimaryCombo);

    hbox->addStretch();

    mProfilesCombo = new KComboBox(this);
    mProfilesCombo->addItem(i18n("Default Profile:"));
    mProfilesCombo->setEnabled(false);
    hbox->addWidget(new QLabel(i18n("Active profile")));
    hbox->addWidget(mProfilesCombo);

    m_controlPanel = new ControlPanel(this);
    m_controlPanel->setConfig(mConfig);
    connect(m_controlPanel, SIGNAL(changed()), this, SIGNAL(changed()));
    Q_FOREACH (KScreen::Output *output, mConfig->outputs()) {
        connect(output, SIGNAL(isConnectedChanged()), this, SLOT(slotOutputConnectedChanged()));
        connect(output, SIGNAL(isEnabledChanged()), this, SLOT(slotOutputEnabledChanged()));
        connect(output, SIGNAL(isPrimaryChanged()), this, SLOT(slotOutputPrimaryChanged()));

        if (!output->isConnected() || !output->isEnabled()) {
            continue;
        }

        mPrimaryCombo->addItem(Utils::outputName(output), output->id());
        if (output->isPrimary()) {
            mPrimaryCombo->setCurrentIndex(mPrimaryCombo->count() - 1);
        }
    }
    layout->addWidget(m_controlPanel);

    mUnifyButton = new KPushButton(i18n("Unify outputs"), this);
    connect(mUnifyButton, SIGNAL(clicked(bool)), this, SLOT(slotUnifyOutputs()));
    layout->addWidget(mUnifyButton);
}

Widget::~Widget()
{
}

KScreen::Config *Widget::currentConfig() const
{
    return mConfig;
}

void Widget::loadQml()
{
    qmlRegisterType<QMLOutput>("org.kde.kscreen", 1, 0, "QMLOutput");
    qmlRegisterType<QMLScreen>("org.kde.kscreen", 1, 0, "QMLScreen");
    qmlRegisterType<IconButton>("org.kde.kscreen", 1, 0, "IconButton");

    qmlRegisterType<KScreen::Output>("org.kde.kscreen", 1, 0, "KScreenOutput");
    qmlRegisterType<KScreen::Edid>("org.kde.kscreen", 1, 0, "KScreenEdid");
    qmlRegisterType<KScreen::Mode>("org.kde.kscreen", 1, 0, "KScreenMode");

    QDir dir = QDir::current();
    dir.cdUp();
    dir.cdUp();
    dir.cd("kcm/qml");
    QDir::setCurrent(dir.path());

    const QString file = QDir::currentPath() + "/main.qml";
    m_declarativeView->engine()->addImportPath(QLatin1String("/usr/lib64/kde4/imports/"));
    m_declarativeView->setSource(QUrl::fromLocalFile(file));

    QGraphicsObject *rootObject = m_declarativeView->rootObject();
    mScreen = rootObject->findChild<QMLScreen*>(QLatin1String("outputView"));
    if (!mScreen) {
        return;
    }

    connect(mScreen, SIGNAL(focusedOutputChanged(QMLOutput*)),
            this, SLOT(slotFocusedOutputChanged(QMLOutput*)));
    connect(mScreen, SIGNAL(focusedOutputChanged(QMLOutput*)),
            this, SIGNAL(changed()));

    mConfig = KScreen::Config::current();
    mScreen->setConfig(mConfig);
}

void Widget::slotFocusedOutputChanged(QMLOutput *output)
{
    m_controlPanel->activateOutput(output->output());
}

void Widget::slotOutputPrimaryChanged()
{
    const int id = qobject_cast<KScreen::Output*>(sender())->id();
    const int index = mPrimaryCombo->findData(id);
    if (index == -1) { // No primary
        mPrimaryCombo->setCurrentIndex(0);
        return;
    }
    mPrimaryCombo->blockSignals(true);
    mPrimaryCombo->setCurrentIndex(index);
    mPrimaryCombo->blockSignals(false);
}

void Widget::slotPrimaryChanged(int index)
{
    const int id = mPrimaryCombo->itemData(index).toInt();
    Q_FOREACH (KScreen::Output *output, mConfig->outputs()) {
        output->blockSignals(true);
        output->setPrimary(output->id() == id);
        output->blockSignals(false);
    }

    Q_EMIT changed();
}

void Widget::slotOutputConnectedChanged()
{
    KScreen::Output *output = qobject_cast<KScreen::Output*>(sender());
    if (output->isConnected()) {
        mPrimaryCombo->addItem(Utils::outputName(output), output->id());
        if (output->isPrimary()) {
            mPrimaryCombo->setCurrentIndex(mPrimaryCombo->count() - 1);
        }
    } else {
        const int index = mPrimaryCombo->findData(output->id());
        mPrimaryCombo->removeItem(index);
    }
}

void Widget::slotOutputEnabledChanged()
{
    int enabledOutputsCnt = 0;
    Q_FOREACH (KScreen::Output *output, mConfig->outputs()) {
        if (output->isEnabled()) {
            ++enabledOutputsCnt;
        }

        if (enabledOutputsCnt > 1) {
            break;
        }
    }

    KScreen::Output *output = qobject_cast<KScreen::Output*>(sender());
    if (output->isEnabled()) {
        mPrimaryCombo->addItem(Utils::outputName(output), output->id());
    } else {
        const int index = mPrimaryCombo->findData(output->id());
        mPrimaryCombo->removeItem(index);
    }

    mUnifyButton->setEnabled(enabledOutputsCnt > 1);
}

void Widget::slotUnifyOutputs()
{
    QMLOutput *base = mScreen->primaryOutput();
    QList<int> clones;

    if (base->isCloneMode()) {
        mScreen->setConfig(mPrevConfig);
        mConfig = mScreen->config();
        m_controlPanel->setConfig(mConfig);

        mPrimaryCombo->setEnabled(true);

        mUnifyButton->setText(i18n("Unify Outputs"));
    } else {
        // Clone the current config, so that we can restore it in case user
        // breaks the cloning
        mPrevConfig = mConfig->clone();

        Q_FOREACH (QMLOutput *output, mScreen->outputs()) {
            if (!output->output()->isConnected()) {
                continue;
            }

            if (!output->output()->isEnabled()) {
                output->hide();
                continue;
            }

            if (base == 0) {
                base = output;
            }

            output->setOutputX(0);
            output->setOutputY(0);
            output->output()->setPos(QPoint(0, 0));
            output->output()->setClones(QList<int>());

            if (base != output) {
                clones << output->output()->id();
                output->setCloneOf(base);
                output->hide();
            }
        }

        base->output()->setClones(clones);
        base->setIsCloneMode(true);

        mScreen->updateOutputsPlacement();

        mPrimaryCombo->setEnabled(false);
        m_controlPanel->setUnifiedOutput(base->output());

        mUnifyButton->setText(i18n("Break unified outputs"));
    }

    Q_EMIT changed();
}

#include "widget.moc"
<|endoftext|>


<commit_before>#include "GHIElectronics_TinyCLR_InteropUtil.h"

const void* TinyCLR_Interop_GetApi(const TinyCLR_Interop_MethodData md, size_t fieldId) {
    const TinyCLR_Interop_ClrObject* self;
    TinyCLR_Interop_ClrValue fld;

    md.InteropManager->GetThisObject(md.InteropManager, md.Stack, self);
    md.InteropManager->GetField(md.InteropManager, self, fieldId, fld);

    return reinterpret_cast<const void*>(fld.Data.Numeric->I);
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetFieldSelf(const TinyCLR_Interop_MethodData md, size_t fieldId) {
    const TinyCLR_Interop_ClrObject* self;
    TinyCLR_Interop_ClrValue fld;

    md.InteropManager->GetThisObject(md.InteropManager, md.Stack, self);
    md.InteropManager->GetField(md.InteropManager, self, fieldId, fld);

    return fld;
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetField(const TinyCLR_Interop_MethodData md, const TinyCLR_Interop_ClrObject* obj, size_t fieldId) {
    TinyCLR_Interop_ClrValue fld;

    md.InteropManager->GetField(md.InteropManager, obj, fieldId, fld);

    return fld;
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetReturn(const TinyCLR_Interop_MethodData md) {
    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    return ret;
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetArgument(const TinyCLR_Interop_MethodData md, uint32_t argIndex) {
    TinyCLR_Interop_ClrValue arg;

	md.InteropManager->GetArgument(md.InteropManager, md.Stack, argIndex, arg);

    return arg;
}
<commit_msg>Removed extra newline<commit_after>#include "GHIElectronics_TinyCLR_InteropUtil.h"

const void* TinyCLR_Interop_GetApi(const TinyCLR_Interop_MethodData md, size_t fieldId) {
    const TinyCLR_Interop_ClrObject* self;
    TinyCLR_Interop_ClrValue fld;

    md.InteropManager->GetThisObject(md.InteropManager, md.Stack, self);
    md.InteropManager->GetField(md.InteropManager, self, fieldId, fld);

    return reinterpret_cast<const void*>(fld.Data.Numeric->I);
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetFieldSelf(const TinyCLR_Interop_MethodData md, size_t fieldId) {
    const TinyCLR_Interop_ClrObject* self;
    TinyCLR_Interop_ClrValue fld;

    md.InteropManager->GetThisObject(md.InteropManager, md.Stack, self);
    md.InteropManager->GetField(md.InteropManager, self, fieldId, fld);

    return fld;
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetField(const TinyCLR_Interop_MethodData md, const TinyCLR_Interop_ClrObject* obj, size_t fieldId) {
    TinyCLR_Interop_ClrValue fld;

    md.InteropManager->GetField(md.InteropManager, obj, fieldId, fld);

    return fld;
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetReturn(const TinyCLR_Interop_MethodData md) {
    TinyCLR_Interop_ClrValue ret;

    md.InteropManager->GetReturn(md.InteropManager, md.Stack, ret);

    return ret;
}

TinyCLR_Interop_ClrValue TinyCLR_Interop_GetArgument(const TinyCLR_Interop_MethodData md, uint32_t argIndex) {
    TinyCLR_Interop_ClrValue arg;

	md.InteropManager->GetArgument(md.InteropManager, md.Stack, argIndex, arg);

    return arg;
}
<|endoftext|>


<commit_before>#include <map>

#include <unordered_map>

#include <Ancona/Framework/EntityFramework/AbstractSystem.hpp>
#include <Ancona/Framework/EntityFramework/SystemManager.hpp>
#include <Ancona/Framework/Serializing/Serializing.hpp>
#include <Ancona/Util/Algorithm.hpp>

using namespace ild;

SystemManager::SystemManager()
{
    _maxEntityId = 0;
}

void SystemManager::Update(float delta, UpdateStepEnum updateStep)
{
    FetchWaitingDependencies();
    for(auto & system : _systems[updateStep])
    {
        system->Update(delta);
        system->DeleteQueuedComponents();
    }
    DeleteQueuedEntities();
}

void SystemManager::DeleteEntity(Entity entity)
{
    Assert(_components.find(entity) != _components.end(),
            "Cannot delete an entity that is not managed by the system manager");

    for(AbstractSystem * system : _components.at(entity))
    {
        system->EntityIsDeleted(entity);
    }

    auto reverseIter = _entitiesReverse.find(entity);
    if(reverseIter != _entitiesReverse.end())
    {
        _entities.erase(reverseIter->second);
        _entitiesReverse.erase(reverseIter);
    }

    _components.erase(entity);
}

void SystemManager::QueueDeleteEntity(Entity entity)
{
    _deleteQueue.push_back(entity);
}

Entity SystemManager::CreateEntity()
{
    Assert(_maxEntityId != ~0u, "Entity key has overflown");

    Entity entity = _maxEntityId++;

    //Create a structure for the entity
    _components[entity];

    return entity;
}

Entity SystemManager::CreateEntity(const std::string & key)
{
    Assert(_entities.find(key) == _entities.end(), "Cannot use the same key for two entities.");

    Entity entity = CreateEntity();
    _entities[key] = entity;
    _entitiesReverse[entity] = key;

    return entity;
}

Entity SystemManager::GetEntity(const std::string & key)
{
    auto entityIter = _entities.find(key);
    if(entityIter == _entities.end())
    {
        return nullentity;
    }
    return entityIter->second;
}

bool SystemManager::ContainsName(std::string & systemName)
{
    return alg::any_of(_keyedSystems,
            [=](std::pair<std::string, AbstractSystem *> & nameSystemPair)
            {
                return nameSystemPair.first == systemName;
            });
}

void SystemManager::RegisterSystem(
        std::string systemName,
        AbstractSystem * system,
        UpdateStepEnum updateStep)
{
    auto & systems = _systems[updateStep];
    Assert(!alg::count_if(systems,[system](std::unique_ptr<AbstractSystem> & ptr)
        {
            return ptr.get() == system;
        }
    ), "A System Manager cannot contain the same system twice");

    systems.emplace_back(system);

    if(systemName != "")
    {
        Assert(!ContainsName(systemName), "System name must be unique.");
        _keyedSystems.emplace_back(systemName, system);
    }
}

void SystemManager::RegisterComponent(Entity entity, AbstractSystem * owningSystem)
{
    Assert(_components.find(entity) != _components.end(),
            "Cannot add a component to an entity that does not exist");
   _components[entity].insert(owningSystem);
   _needDependencyFetch.emplace_back(entity, owningSystem);
}

void SystemManager::UnregisterComponent(Entity entity, AbstractSystem * owningSystem)
{
    Assert(_components.find(entity) != _components.end(),
            "Can not remove a component from an entity that does not exist");
    Assert(_components[entity].find(owningSystem) != _components[entity].end(),
            "Can not remove a component that does not exist");

    _components[entity].erase(owningSystem);
}

void SystemManager::AddEntitySaveableSystemPair(std::string entity, std::string system)
{
    Assert(_entities.count(entity), "Cannot add entity-system saveable pair: Entity " + entity + " does not exist.");
    Assert(alg::count_if(_keyedSystems, [system](std::pair<std::string, AbstractSystem *> sysNamePair)
        {
            return sysNamePair.first == system;
        }
    ), "Cannot add entity-system saveable pair: System " + system + " does not exist or is not keyed.");

    _entitySaveableSystems.emplace_back(entity, system);
}

void SystemManager::DeleteQueuedEntities()
{
    for(Entity & entity : _deleteQueue)
    {
        DeleteEntity(entity);
    }
    _deleteQueue.clear();
}

void SystemManager::FetchWaitingDependencies()
{
    for(auto & entitySystemPair : _needDependencyFetch)
    {
        entitySystemPair.second->FetchComponentDependencies(entitySystemPair.first);
    }
    _needDependencyFetch.clear();
}

void SystemManager::Serialize(Archive & arc)
{
    arc(_entitySaveableSystems, "entity-system-saveables");
}
<commit_msg>remove unnecessary newline<commit_after>#include <map>
#include <unordered_map>

#include <Ancona/Framework/EntityFramework/AbstractSystem.hpp>
#include <Ancona/Framework/EntityFramework/SystemManager.hpp>
#include <Ancona/Framework/Serializing/Serializing.hpp>
#include <Ancona/Util/Algorithm.hpp>

using namespace ild;

SystemManager::SystemManager()
{
    _maxEntityId = 0;
}

void SystemManager::Update(float delta, UpdateStepEnum updateStep)
{
    FetchWaitingDependencies();
    for(auto & system : _systems[updateStep])
    {
        system->Update(delta);
        system->DeleteQueuedComponents();
    }
    DeleteQueuedEntities();
}

void SystemManager::DeleteEntity(Entity entity)
{
    Assert(_components.find(entity) != _components.end(),
            "Cannot delete an entity that is not managed by the system manager");

    for(AbstractSystem * system : _components.at(entity))
    {
        system->EntityIsDeleted(entity);
    }

    auto reverseIter = _entitiesReverse.find(entity);
    if(reverseIter != _entitiesReverse.end())
    {
        _entities.erase(reverseIter->second);
        _entitiesReverse.erase(reverseIter);
    }

    _components.erase(entity);
}

void SystemManager::QueueDeleteEntity(Entity entity)
{
    _deleteQueue.push_back(entity);
}

Entity SystemManager::CreateEntity()
{
    Assert(_maxEntityId != ~0u, "Entity key has overflown");

    Entity entity = _maxEntityId++;

    //Create a structure for the entity
    _components[entity];

    return entity;
}

Entity SystemManager::CreateEntity(const std::string & key)
{
    Assert(_entities.find(key) == _entities.end(), "Cannot use the same key for two entities.");

    Entity entity = CreateEntity();
    _entities[key] = entity;
    _entitiesReverse[entity] = key;

    return entity;
}

Entity SystemManager::GetEntity(const std::string & key)
{
    auto entityIter = _entities.find(key);
    if(entityIter == _entities.end())
    {
        return nullentity;
    }
    return entityIter->second;
}

bool SystemManager::ContainsName(std::string & systemName)
{
    return alg::any_of(_keyedSystems,
            [=](std::pair<std::string, AbstractSystem *> & nameSystemPair)
            {
                return nameSystemPair.first == systemName;
            });
}

void SystemManager::RegisterSystem(
        std::string systemName,
        AbstractSystem * system,
        UpdateStepEnum updateStep)
{
    auto & systems = _systems[updateStep];
    Assert(!alg::count_if(systems,[system](std::unique_ptr<AbstractSystem> & ptr)
        {
            return ptr.get() == system;
        }
    ), "A System Manager cannot contain the same system twice");

    systems.emplace_back(system);

    if(systemName != "")
    {
        Assert(!ContainsName(systemName), "System name must be unique.");
        _keyedSystems.emplace_back(systemName, system);
    }
}

void SystemManager::RegisterComponent(Entity entity, AbstractSystem * owningSystem)
{
    Assert(_components.find(entity) != _components.end(),
            "Cannot add a component to an entity that does not exist");
   _components[entity].insert(owningSystem);
   _needDependencyFetch.emplace_back(entity, owningSystem);
}

void SystemManager::UnregisterComponent(Entity entity, AbstractSystem * owningSystem)
{
    Assert(_components.find(entity) != _components.end(),
            "Can not remove a component from an entity that does not exist");
    Assert(_components[entity].find(owningSystem) != _components[entity].end(),
            "Can not remove a component that does not exist");

    _components[entity].erase(owningSystem);
}

void SystemManager::AddEntitySaveableSystemPair(std::string entity, std::string system)
{
    Assert(_entities.count(entity), "Cannot add entity-system saveable pair: Entity " + entity + " does not exist.");
    Assert(alg::count_if(_keyedSystems, [system](std::pair<std::string, AbstractSystem *> sysNamePair)
        {
            return sysNamePair.first == system;
        }
    ), "Cannot add entity-system saveable pair: System " + system + " does not exist or is not keyed.");

    _entitySaveableSystems.emplace_back(entity, system);
}

void SystemManager::DeleteQueuedEntities()
{
    for(Entity & entity : _deleteQueue)
    {
        DeleteEntity(entity);
    }
    _deleteQueue.clear();
}

void SystemManager::FetchWaitingDependencies()
{
    for(auto & entitySystemPair : _needDependencyFetch)
    {
        entitySystemPair.second->FetchComponentDependencies(entitySystemPair.first);
    }
    _needDependencyFetch.clear();
}

void SystemManager::Serialize(Archive & arc)
{
    arc(_entitySaveableSystems, "entity-system-saveables");
}
<|endoftext|>


<commit_before>// Mutual exclusion spin locks.

#include "types.h"
#include "kernel.hh"
#include "amd64.h"
#include "cpu.hh"
#include "bits.hh"
#include "spinlock.h"
#include "mtrace.h"
#include "condvar.h"
#include "fs.h"
#include "file.hh"
#include "major.h"

#if LOCKSTAT
// The klockstat structure pointed to by spinlocks that want lockstat,
// but have never been acquired.
struct klockstat klockstat_lazy("<lazy>");

static int lockstat_enable;

void lockstat_init(struct spinlock *lk, bool lazy);

static inline struct cpulockstat *
mylockstat(struct spinlock *lk)
{
  return &lk->stat->s.cpu[mycpu()->id];
}

void*
klockstat::operator new(unsigned long nbytes)
{
  assert(nbytes == sizeof(klockstat));
  void* p = kmalloc(sizeof(klockstat), "klockstat");
  if (!p)
    throw_bad_alloc();
  return p;
}

void
klockstat::operator delete(void *p)
{
  kmfree(p, sizeof(klockstat));
}
#endif

static inline void
locking(struct spinlock *lk)
{
#if SPINLOCK_DEBUG
  if(holding(lk)) {
    cprintf("%p\n", __builtin_return_address(0));
    panic("acquire");
  }
#endif

#if LOCKSTAT
  if (lockstat_enable && lk->stat != nullptr) {
    if (lk->stat == &klockstat_lazy)
      lockstat_init(lk, true);
    mylockstat(lk)->locking_ts = rdtsc();
  }
#endif

  mtlock(lk);
}

static inline void
locked(struct spinlock *lk, u64 retries)
{
  mtacquired(lk);

#if SPINLOCK_DEBUG
  // Record info about lock acquisition for debugging.
  lk->cpu = mycpu();
  getcallerpcs(&lk, lk->pcs, NELEM(lk->pcs));
#endif

#if LOCKSTAT
  if (lockstat_enable && lk->stat != nullptr) {
    struct cpulockstat *s = mylockstat(lk);
    if (retries > 0)
      s->contends++;
    s->acquires++;
    s->locked_ts = rdtsc();
  }
#endif
}

static inline void
releasing(struct spinlock *lk)
{
#if SPINLOCK_DEBUG
  if(!holding(lk)) {
    cprintf("lock: %s\n", lk->name);
    panic("release");
  }
#endif

  mtunlock(lk);

#if SPINLOCK_DEBUG
  lk->pcs[0] = 0;
  lk->cpu = 0;
#endif

#if LOCKSTAT
  if (lockstat_enable && lk->stat != nullptr) {
    struct cpulockstat *s = mylockstat(lk);
    u64 ts = rdtsc();
    s->locking += ts - s->locking_ts;
    s->locked += ts - s->locked_ts;
  }
#endif
}

// Check whether this cpu is holding the lock.
#if SPINLOCK_DEBUG
bool
spinlock::holding()
{
  return locked && cpu == mycpu();
}
#endif

#if LOCKSTAT
LIST_HEAD(lockstat_list, klockstat);
static struct lockstat_list lockstat_list = { (struct klockstat*) nullptr };
static struct spinlock lockstat_lock("lockstat");

klockstat::klockstat(const char *name) :
  rcu_freed("klockstat")
{
  magic = LOCKSTAT_MAGIC;
  memset(&s, 0, sizeof(s));
  safestrcpy(s.name, name, sizeof(s.name));
};

void
lockstat_init(struct spinlock *lk, bool lazy)
{
  klockstat *ls = new klockstat(lk->name);
  if (!ls)
    return;

  if (lazy) {
    if (!__sync_bool_compare_and_swap(&lk->stat, &klockstat_lazy, ls)) {
      delete ls;
      return;
    }
  } else {
    lk->stat = ls;
  }

  acquire(&lockstat_lock);
  LIST_INSERT_HEAD(&lockstat_list, lk->stat, link);
  release(&lockstat_lock);
}

static void
lockstat_stop(struct spinlock *lk)
{
  if (lk->stat != nullptr) {
    lk->stat->magic = 0;
    lk->stat = nullptr;
  }
}

void
lockstat_clear(void)
{
  struct klockstat *stat, *tmp;

  acquire(&lockstat_lock);
  LIST_FOREACH_SAFE(stat, &lockstat_list, link, tmp) {
    if (stat->magic == 0) {
      LIST_REMOVE(stat, link);
      // So verifyfree doesn't follow le_next
      stat->link.le_next = 0;
      gc_delayed(stat);
    } else {
      memset(&stat->s.cpu, 0, sizeof(stat->s.cpu));
    }
  }
  release(&lockstat_lock);
}

static int
lockstat_read(sref<struct inode> ip, char *dst, u32 off, u32 n)
{
  static const u64 sz = sizeof(struct lockstat);
  static struct {
    struct klockstat *stat;
    u32 off;
  } cache;

  struct klockstat *stat;
  u32 cur;

  if (off % sz || n < sz)
    return -1;

  acquire(&lockstat_lock);
  if (cache.off == off && cache.stat != nullptr) {
    cur = cache.off;
    stat = cache.stat;
  } else {
    cur = 0;
    stat = LIST_FIRST(&lockstat_list);
  }
  for (; stat != nullptr; stat = LIST_NEXT(stat, link)) {
    struct lockstat *ls = &stat->s;
    if (n < sizeof(*ls))
      break;
    if (cur >= off) {
      memmove(dst, ls, sz);
      dst += sz;
      n -= sz;
    }
    cur += sz;
  }
  release(&lockstat_lock);

  if (cur < off) {
    cache.off = 0;
    cache.stat = (struct klockstat*) nullptr;
    return 0;
  }

  cache.off = cur;
  cache.stat = stat;
  return cur - off;
}

static int
lockstat_write(sref<struct inode> ip, const char *buf, u32 off, u32 n)
{
  int cmd = buf[0] - '0';

  switch(cmd) {
  case LOCKSTAT_START:
    lockstat_enable = 1;
    break;
  case LOCKSTAT_STOP:
    lockstat_enable = 0;
    break;
  case LOCKSTAT_CLEAR:
    lockstat_clear();
    break;
  default:
    return -1;
  }
  return n;
}

void
initlockstat(void)
{
  devsw[MAJ_LOCKSTAT].write = lockstat_write;
  devsw[MAJ_LOCKSTAT].read = lockstat_read;
}
#else
void
initlockstat(void)
{
}
#endif

spinlock::spinlock(spinlock &&o)
  : locked(o.locked.load())
#if SPINLOCK_DEBUG
    , name(o.name)
    , cpu(o.cpu)
#endif
#if LOCKSTAT
    , stat(o.stat)
#endif
{
#if SPINLOCK_DEBUG
  memcpy(&pcs, &o.pcs, sizeof(pcs));
#endif
#if LOCKSTAT
  lockstat_stop(&o);
#endif
}

spinlock &
spinlock::operator=(spinlock &&o)
{
#if LOCKSTAT
  lockstat_stop(this);
#endif
  locked = o.locked.load();
#if SPINLOCK_DEBUG
  name = o.name;
  cpu = o.cpu;
  memcpy(&pcs, &o.pcs, sizeof(pcs));
#endif
#if LOCKSTAT
  stat = o.stat;
  o.stat = nullptr;
#endif
  return *this;
}

#if LOCKSTAT
spinlock::~spinlock()
{
  lockstat_stop(this);
}
#endif

bool
spinlock::try_acquire()
{
  pushcli();
  locking(this);
  if (locked.exchange(1) != 0) {
      popcli();
      return false;
  }
  ::locked(this, 0);
  return true;
}

// Acquire the lock.
// Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause
// other CPUs to waste time spinning to acquire it.
void
spinlock::acquire()
{
  u64 retries;

  pushcli();
  locking(this);

  retries = 0;
  while (locked.exchange(1) != 0) {
    retries++;
    nop_pause();
  }
  ::locked(this, retries);
}

// Release the lock.
void
spinlock::release()
{
  releasing(this);

  // The xchg serializes, so that reads before release are
  // not reordered after it.  The 1996 PentiumPro manual (Volume 3,
  // 7.2) says reads can be carried out speculatively and in
  // any order, which implies we need to serialize here.
  // But the 2007 Intel 64 Architecture Memory Ordering White
  // Paper says that Intel 64 and IA-32 will not move a load
  // after a store. So lock->locked = 0 would work here.
  // The xchg being asm volatile ensures gcc emits it after
  // the above assignments (and after the critical section).
  locked.exchange(0); // could just be locked.store(0)?

  popcli();
}
<commit_msg>spinlock: Use acquire/release memory ordering<commit_after>// Mutual exclusion spin locks.

#include "types.h"
#include "kernel.hh"
#include "amd64.h"
#include "cpu.hh"
#include "bits.hh"
#include "spinlock.h"
#include "mtrace.h"
#include "condvar.h"
#include "fs.h"
#include "file.hh"
#include "major.h"

#if LOCKSTAT
// The klockstat structure pointed to by spinlocks that want lockstat,
// but have never been acquired.
struct klockstat klockstat_lazy("<lazy>");

static int lockstat_enable;

void lockstat_init(struct spinlock *lk, bool lazy);

static inline struct cpulockstat *
mylockstat(struct spinlock *lk)
{
  return &lk->stat->s.cpu[mycpu()->id];
}

void*
klockstat::operator new(unsigned long nbytes)
{
  assert(nbytes == sizeof(klockstat));
  void* p = kmalloc(sizeof(klockstat), "klockstat");
  if (!p)
    throw_bad_alloc();
  return p;
}

void
klockstat::operator delete(void *p)
{
  kmfree(p, sizeof(klockstat));
}
#endif

static inline void
locking(struct spinlock *lk)
{
#if SPINLOCK_DEBUG
  if(holding(lk)) {
    cprintf("%p\n", __builtin_return_address(0));
    panic("acquire");
  }
#endif

#if LOCKSTAT
  if (lockstat_enable && lk->stat != nullptr) {
    if (lk->stat == &klockstat_lazy)
      lockstat_init(lk, true);
    mylockstat(lk)->locking_ts = rdtsc();
  }
#endif

  mtlock(lk);
}

static inline void
locked(struct spinlock *lk, u64 retries)
{
  mtacquired(lk);

#if SPINLOCK_DEBUG
  // Record info about lock acquisition for debugging.
  lk->cpu = mycpu();
  getcallerpcs(&lk, lk->pcs, NELEM(lk->pcs));
#endif

#if LOCKSTAT
  if (lockstat_enable && lk->stat != nullptr) {
    struct cpulockstat *s = mylockstat(lk);
    if (retries > 0)
      s->contends++;
    s->acquires++;
    s->locked_ts = rdtsc();
  }
#endif
}

static inline void
releasing(struct spinlock *lk)
{
#if SPINLOCK_DEBUG
  if(!holding(lk)) {
    cprintf("lock: %s\n", lk->name);
    panic("release");
  }
#endif

  mtunlock(lk);

#if SPINLOCK_DEBUG
  lk->pcs[0] = 0;
  lk->cpu = 0;
#endif

#if LOCKSTAT
  if (lockstat_enable && lk->stat != nullptr) {
    struct cpulockstat *s = mylockstat(lk);
    u64 ts = rdtsc();
    s->locking += ts - s->locking_ts;
    s->locked += ts - s->locked_ts;
  }
#endif
}

// Check whether this cpu is holding the lock.
#if SPINLOCK_DEBUG
bool
spinlock::holding()
{
  return locked && cpu == mycpu();
}
#endif

#if LOCKSTAT
LIST_HEAD(lockstat_list, klockstat);
static struct lockstat_list lockstat_list = { (struct klockstat*) nullptr };
static struct spinlock lockstat_lock("lockstat");

klockstat::klockstat(const char *name) :
  rcu_freed("klockstat")
{
  magic = LOCKSTAT_MAGIC;
  memset(&s, 0, sizeof(s));
  safestrcpy(s.name, name, sizeof(s.name));
};

void
lockstat_init(struct spinlock *lk, bool lazy)
{
  klockstat *ls = new klockstat(lk->name);
  if (!ls)
    return;

  if (lazy) {
    if (!__sync_bool_compare_and_swap(&lk->stat, &klockstat_lazy, ls)) {
      delete ls;
      return;
    }
  } else {
    lk->stat = ls;
  }

  acquire(&lockstat_lock);
  LIST_INSERT_HEAD(&lockstat_list, lk->stat, link);
  release(&lockstat_lock);
}

static void
lockstat_stop(struct spinlock *lk)
{
  if (lk->stat != nullptr) {
    lk->stat->magic = 0;
    lk->stat = nullptr;
  }
}

void
lockstat_clear(void)
{
  struct klockstat *stat, *tmp;

  acquire(&lockstat_lock);
  LIST_FOREACH_SAFE(stat, &lockstat_list, link, tmp) {
    if (stat->magic == 0) {
      LIST_REMOVE(stat, link);
      // So verifyfree doesn't follow le_next
      stat->link.le_next = 0;
      gc_delayed(stat);
    } else {
      memset(&stat->s.cpu, 0, sizeof(stat->s.cpu));
    }
  }
  release(&lockstat_lock);
}

static int
lockstat_read(sref<struct inode> ip, char *dst, u32 off, u32 n)
{
  static const u64 sz = sizeof(struct lockstat);
  static struct {
    struct klockstat *stat;
    u32 off;
  } cache;

  struct klockstat *stat;
  u32 cur;

  if (off % sz || n < sz)
    return -1;

  acquire(&lockstat_lock);
  if (cache.off == off && cache.stat != nullptr) {
    cur = cache.off;
    stat = cache.stat;
  } else {
    cur = 0;
    stat = LIST_FIRST(&lockstat_list);
  }
  for (; stat != nullptr; stat = LIST_NEXT(stat, link)) {
    struct lockstat *ls = &stat->s;
    if (n < sizeof(*ls))
      break;
    if (cur >= off) {
      memmove(dst, ls, sz);
      dst += sz;
      n -= sz;
    }
    cur += sz;
  }
  release(&lockstat_lock);

  if (cur < off) {
    cache.off = 0;
    cache.stat = (struct klockstat*) nullptr;
    return 0;
  }

  cache.off = cur;
  cache.stat = stat;
  return cur - off;
}

static int
lockstat_write(sref<struct inode> ip, const char *buf, u32 off, u32 n)
{
  int cmd = buf[0] - '0';

  switch(cmd) {
  case LOCKSTAT_START:
    lockstat_enable = 1;
    break;
  case LOCKSTAT_STOP:
    lockstat_enable = 0;
    break;
  case LOCKSTAT_CLEAR:
    lockstat_clear();
    break;
  default:
    return -1;
  }
  return n;
}

void
initlockstat(void)
{
  devsw[MAJ_LOCKSTAT].write = lockstat_write;
  devsw[MAJ_LOCKSTAT].read = lockstat_read;
}
#else
void
initlockstat(void)
{
}
#endif

spinlock::spinlock(spinlock &&o)
  : locked(o.locked.load())
#if SPINLOCK_DEBUG
    , name(o.name)
    , cpu(o.cpu)
#endif
#if LOCKSTAT
    , stat(o.stat)
#endif
{
#if SPINLOCK_DEBUG
  memcpy(&pcs, &o.pcs, sizeof(pcs));
#endif
#if LOCKSTAT
  lockstat_stop(&o);
#endif
}

spinlock &
spinlock::operator=(spinlock &&o)
{
#if LOCKSTAT
  lockstat_stop(this);
#endif
  locked = o.locked.load();
#if SPINLOCK_DEBUG
  name = o.name;
  cpu = o.cpu;
  memcpy(&pcs, &o.pcs, sizeof(pcs));
#endif
#if LOCKSTAT
  stat = o.stat;
  o.stat = nullptr;
#endif
  return *this;
}

#if LOCKSTAT
spinlock::~spinlock()
{
  lockstat_stop(this);
}
#endif

bool
spinlock::try_acquire()
{
  pushcli();
  locking(this);
  if (locked.exchange(1) != 0) {
      popcli();
      return false;
  }
  ::locked(this, 0);
  return true;
}

// Acquire the lock.
// Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause
// other CPUs to waste time spinning to acquire it.
void
spinlock::acquire()
{
  u64 retries;

  pushcli();
  locking(this);

  retries = 0;
  while (locked.exchange(1, std::memory_order_acquire) != 0) {
    retries++;
    nop_pause();
  }
  ::locked(this, retries);
}

// Release the lock.
void
spinlock::release()
{
  releasing(this);

  locked.store(0, std::memory_order_release);

  popcli();
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "RemoveUnreachable.h"

#include "DexUtil.h"
#include "Resolver.h"

namespace {

template<class T>
bool is_seed(const T& t) {
  return t->rstate.is_seed() || t->rstate.is_renamed_seed();
}

bool signatures_match(const DexMethod* a, const DexMethod* b) {
  return a->get_name() == b->get_name() && a->get_proto() == b->get_proto();
}

bool implements_library_method(const DexMethod* to_check, const DexClass* cls) {
  if (!cls) return false;
  if (cls->is_external()) {
    for (auto const& m : cls->get_vmethods()) {
      if (signatures_match(to_check, m)) {
        return true;
      }
    }
  }
  auto const& superclass = type_class(cls->get_super_class());
  if (implements_library_method(to_check, superclass)) {
    return true;
  }
  for (auto const& interface : cls->get_interfaces()->get_type_list()) {
    if (implements_library_method(to_check, type_class(interface))) {
      return true;
    }
  }
  return false;
}

void trace_stats(const char* label, DexStoresVector& stores) {
  size_t nclasses = 0;
  size_t nfields = 0;
  size_t nmethods = 0;
  for (auto const& dex : DexStoreClassesIterator(stores)) {
    nclasses += dex.size();
    for (auto const& cls : dex) {
      nfields += cls->get_ifields().size();
      nfields += cls->get_sfields().size();
      nmethods += cls->get_dmethods().size();
      nmethods += cls->get_vmethods().size();
    }
  }
  TRACE(RMU, 1, "%s: %lu classes, %lu fields, %lu methods\n",
        label, nclasses, nfields, nmethods);
}

struct InheritanceGraph {
  InheritanceGraph(DexStoresVector& stores) {
    for (auto const& dex : DexStoreClassesIterator(stores)) {
      for (auto const& cls : dex) {
        add_child(cls->get_type(), cls->get_type());
      }
    }
  }

  const std::unordered_set<DexType*>& get_descendants(DexType* type) {
    return m_inheritors[type];
  }

 private:
  void add_child(DexType* child, DexType* ancestor) {
    auto const& ancestor_cls = type_class(ancestor);
    if (!ancestor_cls) return;
    auto const& super_type = ancestor_cls->get_super_class();
    if (super_type) {
      TRACE(RMU, 3, "Child %s of %s\n", SHOW(child), SHOW(super_type));
      m_inheritors[super_type].insert(child);
      add_child(child, super_type);
    }
    auto const& interfaces = ancestor_cls->get_interfaces()->get_type_list();
    for (auto const& interface : interfaces) {
      TRACE(RMU, 3, "Child %s of %s\n", SHOW(child), SHOW(interface));
      m_inheritors[interface].insert(child);
      add_child(child, interface);
    }
  }

 private:
  std::unordered_map<DexType*, std::unordered_set<DexType*>> m_inheritors;
};

struct UnreachableCodeRemover {
  UnreachableCodeRemover(DexStoresVector& stores)
    : m_stores(stores),
      m_inheritance_graph(stores)
  {}

  void mark_sweep() {
    mark();
    sweep();
  }

 private:
  void mark(const DexClass* cls) {
    if (!cls) return;
    m_marked_classes.emplace(cls);
  }

  void mark(const DexField* field) {
    if (!field) return;
    m_marked_fields.emplace(field);
  }

  void mark(const DexMethod* method) {
    if (!method) return;
    m_marked_methods.emplace(method);
  }

  bool marked(const DexClass* cls) {
    return m_marked_classes.count(cls);
  }

  bool marked(const DexField* field) {
    return m_marked_fields.count(field);
  }

  bool marked(const DexMethod* method) {
    return m_marked_methods.count(method);
  }

  template<class T>
  void gather_and_visit(T t) {
    std::vector<DexType*> types;
    std::vector<DexField*> fields;
    std::vector<DexMethod*> methods;
    t->gather_types(types);
    t->gather_fields(fields);
    t->gather_methods(methods);
    for (auto const& t : types) {
      visit(type_class(t));
    }
    for (auto const& f : fields) {
      visit(f);
    }
    for (auto const& m : methods) {
      visit(m);
    }
  }

  void visit(const DexClass* cls) {
    if (!cls) return;
    if (marked(cls)) return;
    TRACE(RMU, 3, "Visiting class: %s\n", SHOW(cls));
    mark(cls);
    for (auto& m : cls->get_dmethods()) {
      if (is_init(m)) visit(m);
      if (is_clinit(m)) visit(m);
    }
    visit(type_class(cls->get_super_class()));
    for (auto const& t : cls->get_interfaces()->get_type_list()) {
      visit(type_class(t));
    }
    auto const& annoset = cls->get_anno_set();
    if (annoset) {
      gather_and_visit(annoset);
    }
  }

  void visit(DexField* field) {
    if (!field) return;
    if (marked(field)) return;
    TRACE(RMU, 3, "Visiting field: %s\n", SHOW(field));
    mark(field);
    if (!field->is_concrete()) {
      auto const& realfield = resolve_field(
        field->get_class(), field->get_name(), field->get_type());
      visit(realfield);
    }
    gather_and_visit(field);
    visit(type_class(field->get_class()));
    visit(type_class(field->get_type()));
  }

  void visit(DexMethod* method) {
    if (!method) return;
    if (marked(method)) return;
    TRACE(RMU, 3, "Visiting method: %s\n", SHOW(method));
    mark(method);
    visit(resolve_method(method, MethodSearch::Any));
    visit(resolve_intf_methodref(method));
    gather_and_visit(method);
    visit(type_class(method->get_class()));
    visit(type_class(method->get_proto()->get_rtype()));
    for (auto const& t : method->get_proto()->get_args()->get_type_list()) {
      visit(type_class(t));
    }
    if (method->is_virtual() || !method->is_concrete()) {
      // If we're keeping an interface method, we have to keep its
      // implementations.  Annoyingly, the implementation might be defined on a
      // super class of the class that implements the interface.
      auto const& cls = method->get_class();
      auto const& children = m_inheritance_graph.get_descendants(cls);
      for (auto child : children) {
        while (true) {
          auto child_cls = type_class(child);
          if (!child_cls || child_cls->is_external()) {
            break;
          }
          for (auto const& m : child_cls->get_vmethods()) {
            if (signatures_match(method, m)) {
              visit(m);
            }
          }
          child = child_cls->get_super_class();
        }
      }
    }
  }

  void mark() {
    for (auto const& dex : DexStoreClassesIterator(m_stores)) {
      for (auto const& cls : dex) {
        if (is_seed(cls)) {
          TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(cls));
          visit(cls);
        }
        for (auto const& f : cls->get_ifields()) {
          if (is_seed(f) || is_volatile(f)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(f));
            visit(f);
          }
        }
        for (auto const& f : cls->get_sfields()) {
          if (is_seed(f)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(f));
            visit(f);
          }
        }
        for (auto const& m : cls->get_dmethods()) {
          if (is_seed(m)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(m));
            visit(m);
          }
        }
        for (auto const& m : cls->get_vmethods()) {
          if (is_seed(m) || implements_library_method(m, cls)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(m));
            visit(m);
          }
        }
      }
    }
  }

  template<class Container, class Marked>
  void sweep_if_unmarked(
    Container& c,
    const std::unordered_set<Marked>& marked
  ) {
    c.erase(
      std::remove_if(
        c.begin(), c.end(),
        [&](const Marked& m) {
          if (marked.count(m) == 0) {
            TRACE(RMU, 2, "Removing %s\n", SHOW(m));
            return true;
          }
          return false;
        }),
      c.end());
  }

  void sweep() {
    for (auto& dex : DexStoreClassesIterator(m_stores)) {
      sweep_if_unmarked(dex, m_marked_classes);
      for (auto const& cls : dex) {
        sweep_if_unmarked(cls->get_ifields(), m_marked_fields);
        sweep_if_unmarked(cls->get_sfields(), m_marked_fields);
        sweep_if_unmarked(cls->get_dmethods(), m_marked_methods);
        sweep_if_unmarked(cls->get_vmethods(), m_marked_methods);
      }
    }
  }

 private:
  DexStoresVector& m_stores;
  InheritanceGraph m_inheritance_graph;
  std::unordered_set<const DexClass*> m_marked_classes;
  std::unordered_set<const DexField*> m_marked_fields;
  std::unordered_set<const DexMethod*> m_marked_methods;
};

}

void RemoveUnreachablePass::run_pass(
  DexStoresVector& stores,
  ConfigFiles& cfg,
  PassManager& pm
) {
  if (!cfg.using_seeds) {
    TRACE(RMU, 1, "No seeds information.  Not running RemoveUnreachable.\n");
    return;
  }
  UnreachableCodeRemover ucr(stores);
  trace_stats("before", stores);
  ucr.mark_sweep();
  trace_stats("after", stores);
}
<commit_msg>Do not remove canary classes<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "RemoveUnreachable.h"

#include "DexUtil.h"
#include "Resolver.h"

namespace {

template<class T>
bool is_seed(const T& t) {
  return t->rstate.is_seed() || t->rstate.is_renamed_seed();
}

bool is_canary(const DexClass* cls) {
  return strstr(cls->get_name()->c_str(), "Canary");
}

bool signatures_match(const DexMethod* a, const DexMethod* b) {
  return a->get_name() == b->get_name() && a->get_proto() == b->get_proto();
}

bool implements_library_method(const DexMethod* to_check, const DexClass* cls) {
  if (!cls) return false;
  if (cls->is_external()) {
    for (auto const& m : cls->get_vmethods()) {
      if (signatures_match(to_check, m)) {
        return true;
      }
    }
  }
  auto const& superclass = type_class(cls->get_super_class());
  if (implements_library_method(to_check, superclass)) {
    return true;
  }
  for (auto const& interface : cls->get_interfaces()->get_type_list()) {
    if (implements_library_method(to_check, type_class(interface))) {
      return true;
    }
  }
  return false;
}

void trace_stats(const char* label, DexStoresVector& stores) {
  size_t nclasses = 0;
  size_t nfields = 0;
  size_t nmethods = 0;
  for (auto const& dex : DexStoreClassesIterator(stores)) {
    nclasses += dex.size();
    for (auto const& cls : dex) {
      nfields += cls->get_ifields().size();
      nfields += cls->get_sfields().size();
      nmethods += cls->get_dmethods().size();
      nmethods += cls->get_vmethods().size();
    }
  }
  TRACE(RMU, 1, "%s: %lu classes, %lu fields, %lu methods\n",
        label, nclasses, nfields, nmethods);
}

struct InheritanceGraph {
  InheritanceGraph(DexStoresVector& stores) {
    for (auto const& dex : DexStoreClassesIterator(stores)) {
      for (auto const& cls : dex) {
        add_child(cls->get_type(), cls->get_type());
      }
    }
  }

  const std::unordered_set<DexType*>& get_descendants(DexType* type) {
    return m_inheritors[type];
  }

 private:
  void add_child(DexType* child, DexType* ancestor) {
    auto const& ancestor_cls = type_class(ancestor);
    if (!ancestor_cls) return;
    auto const& super_type = ancestor_cls->get_super_class();
    if (super_type) {
      TRACE(RMU, 3, "Child %s of %s\n", SHOW(child), SHOW(super_type));
      m_inheritors[super_type].insert(child);
      add_child(child, super_type);
    }
    auto const& interfaces = ancestor_cls->get_interfaces()->get_type_list();
    for (auto const& interface : interfaces) {
      TRACE(RMU, 3, "Child %s of %s\n", SHOW(child), SHOW(interface));
      m_inheritors[interface].insert(child);
      add_child(child, interface);
    }
  }

 private:
  std::unordered_map<DexType*, std::unordered_set<DexType*>> m_inheritors;
};

struct UnreachableCodeRemover {
  UnreachableCodeRemover(DexStoresVector& stores)
    : m_stores(stores),
      m_inheritance_graph(stores)
  {}

  void mark_sweep() {
    mark();
    sweep();
  }

 private:
  void mark(const DexClass* cls) {
    if (!cls) return;
    m_marked_classes.emplace(cls);
  }

  void mark(const DexField* field) {
    if (!field) return;
    m_marked_fields.emplace(field);
  }

  void mark(const DexMethod* method) {
    if (!method) return;
    m_marked_methods.emplace(method);
  }

  bool marked(const DexClass* cls) {
    return m_marked_classes.count(cls);
  }

  bool marked(const DexField* field) {
    return m_marked_fields.count(field);
  }

  bool marked(const DexMethod* method) {
    return m_marked_methods.count(method);
  }

  template<class T>
  void gather_and_visit(T t) {
    std::vector<DexType*> types;
    std::vector<DexField*> fields;
    std::vector<DexMethod*> methods;
    t->gather_types(types);
    t->gather_fields(fields);
    t->gather_methods(methods);
    for (auto const& t : types) {
      visit(type_class(t));
    }
    for (auto const& f : fields) {
      visit(f);
    }
    for (auto const& m : methods) {
      visit(m);
    }
  }

  void visit(const DexClass* cls) {
    if (!cls) return;
    if (marked(cls)) return;
    TRACE(RMU, 3, "Visiting class: %s\n", SHOW(cls));
    mark(cls);
    for (auto& m : cls->get_dmethods()) {
      if (is_init(m)) visit(m);
      if (is_clinit(m)) visit(m);
    }
    visit(type_class(cls->get_super_class()));
    for (auto const& t : cls->get_interfaces()->get_type_list()) {
      visit(type_class(t));
    }
    auto const& annoset = cls->get_anno_set();
    if (annoset) {
      gather_and_visit(annoset);
    }
  }

  void visit(DexField* field) {
    if (!field) return;
    if (marked(field)) return;
    TRACE(RMU, 3, "Visiting field: %s\n", SHOW(field));
    mark(field);
    if (!field->is_concrete()) {
      auto const& realfield = resolve_field(
        field->get_class(), field->get_name(), field->get_type());
      visit(realfield);
    }
    gather_and_visit(field);
    visit(type_class(field->get_class()));
    visit(type_class(field->get_type()));
  }

  void visit(DexMethod* method) {
    if (!method) return;
    if (marked(method)) return;
    TRACE(RMU, 3, "Visiting method: %s\n", SHOW(method));
    mark(method);
    visit(resolve_method(method, MethodSearch::Any));
    visit(resolve_intf_methodref(method));
    gather_and_visit(method);
    visit(type_class(method->get_class()));
    visit(type_class(method->get_proto()->get_rtype()));
    for (auto const& t : method->get_proto()->get_args()->get_type_list()) {
      visit(type_class(t));
    }
    if (method->is_virtual() || !method->is_concrete()) {
      // If we're keeping an interface method, we have to keep its
      // implementations.  Annoyingly, the implementation might be defined on a
      // super class of the class that implements the interface.
      auto const& cls = method->get_class();
      auto const& children = m_inheritance_graph.get_descendants(cls);
      for (auto child : children) {
        while (true) {
          auto child_cls = type_class(child);
          if (!child_cls || child_cls->is_external()) {
            break;
          }
          for (auto const& m : child_cls->get_vmethods()) {
            if (signatures_match(method, m)) {
              visit(m);
            }
          }
          child = child_cls->get_super_class();
        }
      }
    }
  }

  void mark() {
    for (auto const& dex : DexStoreClassesIterator(m_stores)) {
      for (auto const& cls : dex) {
        if (is_seed(cls) || is_canary(cls)) {
          TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(cls));
          visit(cls);
        }
        for (auto const& f : cls->get_ifields()) {
          if (is_seed(f) || is_volatile(f)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(f));
            visit(f);
          }
        }
        for (auto const& f : cls->get_sfields()) {
          if (is_seed(f)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(f));
            visit(f);
          }
        }
        for (auto const& m : cls->get_dmethods()) {
          if (is_seed(m)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(m));
            visit(m);
          }
        }
        for (auto const& m : cls->get_vmethods()) {
          if (is_seed(m) || implements_library_method(m, cls)) {
            TRACE(RMU, 2, "Visiting seed: %s\n", SHOW(m));
            visit(m);
          }
        }
      }
    }
  }

  template<class Container, class Marked>
  void sweep_if_unmarked(
    Container& c,
    const std::unordered_set<Marked>& marked
  ) {
    c.erase(
      std::remove_if(
        c.begin(), c.end(),
        [&](const Marked& m) {
          if (marked.count(m) == 0) {
            TRACE(RMU, 2, "Removing %s\n", SHOW(m));
            return true;
          }
          return false;
        }),
      c.end());
  }

  void sweep() {
    for (auto& dex : DexStoreClassesIterator(m_stores)) {
      sweep_if_unmarked(dex, m_marked_classes);
      for (auto const& cls : dex) {
        sweep_if_unmarked(cls->get_ifields(), m_marked_fields);
        sweep_if_unmarked(cls->get_sfields(), m_marked_fields);
        sweep_if_unmarked(cls->get_dmethods(), m_marked_methods);
        sweep_if_unmarked(cls->get_vmethods(), m_marked_methods);
      }
    }
  }

 private:
  DexStoresVector& m_stores;
  InheritanceGraph m_inheritance_graph;
  std::unordered_set<const DexClass*> m_marked_classes;
  std::unordered_set<const DexField*> m_marked_fields;
  std::unordered_set<const DexMethod*> m_marked_methods;
};

}

void RemoveUnreachablePass::run_pass(
  DexStoresVector& stores,
  ConfigFiles& cfg,
  PassManager& pm
) {
  if (!cfg.using_seeds) {
    TRACE(RMU, 1, "No seeds information.  Not running RemoveUnreachable.\n");
    return;
  }
  UnreachableCodeRemover ucr(stores);
  trace_stats("before", stores);
  ucr.mark_sweep();
  trace_stats("after", stores);
}
<|endoftext|>