<commit_before>#include "xchainer/python/array.h"

#include <algorithm>

#include "xchainer/array.h"

namespace xchainer {

namespace py = pybind11;

void InitXchainerArray(pybind11::module& m) {
    py::class_<Array, std::shared_ptr<Array>>{m, "Array"}
        .def(py::init([](const Shape& shape, Dtype dtype, py::list list) {
            auto total_size = shape.total_size();
            auto bytes = GetElementSize(dtype) * total_size;
            if (static_cast<size_t>(total_size) != list.size()) {
                throw DimensionError("Invalid data length");
            }

            std::shared_ptr<void> ptr = std::make_unique<uint8_t[]>(bytes);
            auto func = [&](auto dummy) {
                using T = decltype(dummy);
                std::transform(list.begin(), list.end(), reinterpret_cast<T*>(ptr.get()), [](auto& item) { return py::cast<T>(item); });
            };
            switch (dtype) {
                case Dtype::kBool:
                    func(static_cast<bool>(0));
                    break;
                case Dtype::kInt8:
                    func(static_cast<int8_t>(0));
                    break;
                case Dtype::kInt16:
                    func(static_cast<int16_t>(0));
                    break;
                case Dtype::kInt32:
                    func(static_cast<int32_t>(0));
                    break;
                case Dtype::kInt64:
                    func(static_cast<int64_t>(0));
                    break;
                case Dtype::kUInt8:
                    func(static_cast<uint8_t>(0));
                    break;
                case Dtype::kFloat32:
                    func(static_cast<float>(0));
                    break;
                case Dtype::kFloat64:
                    func(static_cast<double>(0));
                    break;
                default:
                    assert(0);
            }
            return Array{shape, dtype, ptr};
        }))
        .def_property_readonly("dtype", &Array::dtype)
        .def_property_readonly("shape", &Array::shape)
        .def_property_readonly("is_contiguous", &Array::is_contiguous)
        .def_property_readonly("total_size", &Array::total_size)
        .def_property_readonly("element_bytes", &Array::element_bytes)
        .def_property_readonly("total_bytes", &Array::total_bytes)
        .def_property_readonly("offset", &Array::offset)
        .def_property_readonly("debug_flat_data",
                               [](const Array& self) {  // This method is a stub for testing
                                   py::list list;
                                   auto size = self.total_size();
                                   auto func = [&](auto dummy) {
                                       using T = decltype(dummy);
                                       const T& data = *std::static_pointer_cast<const T>(self.data());
                                       for (int64_t i = 0; i < size; ++i) {
                                           list.append((&data)[i]);
                                       }
                                   };
                                   switch (self.dtype()) {
                                       case Dtype::kBool:
                                           func(static_cast<bool>(0));
                                           break;
                                       case Dtype::kInt8:
                                           func(static_cast<int8_t>(0));
                                           break;
                                       case Dtype::kInt16:
                                           func(static_cast<int16_t>(0));
                                           break;
                                       case Dtype::kInt32:
                                           func(static_cast<int32_t>(0));
                                           break;
                                       case Dtype::kInt64:
                                           func(static_cast<int64_t>(0));
                                           break;
                                       case Dtype::kUInt8:
                                           func(static_cast<uint8_t>(0));
                                           break;
                                       case Dtype::kFloat32:
                                           func(static_cast<float>(0));
                                           break;
                                       case Dtype::kFloat64:
                                           func(static_cast<double>(0));
                                           break;
                                       default:
                                           assert(0);
                                   }
                                   return list;
                               })
        .def("__add__", [](const Array& lhs, const Array& rhs) { return lhs.Add(rhs); })
        .def("__iadd__", [](Array& lhs, const Array& rhs) { return lhs.IAdd(rhs); })
        .def("__mul__", [](const Array& lhs, const Array& rhs) { return lhs.Mul(rhs); })
        .def("__imul__", [](Array& lhs, const Array& rhs) { return lhs.IMul(rhs); });
}

}  // namespace xchainer
<commit_msg>Use function pointer instead of lambda<commit_after>#include "xchainer/python/array.h"

#include <algorithm>

#include "xchainer/array.h"

namespace xchainer {

namespace py = pybind11;

void InitXchainerArray(pybind11::module& m) {
    py::class_<Array, std::shared_ptr<Array>>{m, "Array"}
        .def(py::init([](const Shape& shape, Dtype dtype, py::list list) {
            auto total_size = shape.total_size();
            auto bytes = GetElementSize(dtype) * total_size;
            if (static_cast<size_t>(total_size) != list.size()) {
                throw DimensionError("Invalid data length");
            }

            std::shared_ptr<void> ptr = std::make_unique<uint8_t[]>(bytes);
            auto func = [&](auto dummy) {
                using T = decltype(dummy);
                std::transform(list.begin(), list.end(), reinterpret_cast<T*>(ptr.get()), [](auto& item) { return py::cast<T>(item); });
            };
            switch (dtype) {
                case Dtype::kBool:
                    func(static_cast<bool>(0));
                    break;
                case Dtype::kInt8:
                    func(static_cast<int8_t>(0));
                    break;
                case Dtype::kInt16:
                    func(static_cast<int16_t>(0));
                    break;
                case Dtype::kInt32:
                    func(static_cast<int32_t>(0));
                    break;
                case Dtype::kInt64:
                    func(static_cast<int64_t>(0));
                    break;
                case Dtype::kUInt8:
                    func(static_cast<uint8_t>(0));
                    break;
                case Dtype::kFloat32:
                    func(static_cast<float>(0));
                    break;
                case Dtype::kFloat64:
                    func(static_cast<double>(0));
                    break;
                default:
                    assert(0);
            }
            return Array{shape, dtype, ptr};
        }))
        .def_property_readonly("dtype", &Array::dtype)
        .def_property_readonly("shape", &Array::shape)
        .def_property_readonly("is_contiguous", &Array::is_contiguous)
        .def_property_readonly("total_size", &Array::total_size)
        .def_property_readonly("element_bytes", &Array::element_bytes)
        .def_property_readonly("total_bytes", &Array::total_bytes)
        .def_property_readonly("offset", &Array::offset)
        .def_property_readonly("debug_flat_data",
                               [](const Array& self) {  // This method is a stub for testing
                                   py::list list;
                                   auto size = self.total_size();
                                   auto func = [&](auto dummy) {
                                       using T = decltype(dummy);
                                       const T& data = *std::static_pointer_cast<const T>(self.data());
                                       for (int64_t i = 0; i < size; ++i) {
                                           list.append((&data)[i]);
                                       }
                                   };
                                   switch (self.dtype()) {
                                       case Dtype::kBool:
                                           func(static_cast<bool>(0));
                                           break;
                                       case Dtype::kInt8:
                                           func(static_cast<int8_t>(0));
                                           break;
                                       case Dtype::kInt16:
                                           func(static_cast<int16_t>(0));
                                           break;
                                       case Dtype::kInt32:
                                           func(static_cast<int32_t>(0));
                                           break;
                                       case Dtype::kInt64:
                                           func(static_cast<int64_t>(0));
                                           break;
                                       case Dtype::kUInt8:
                                           func(static_cast<uint8_t>(0));
                                           break;
                                       case Dtype::kFloat32:
                                           func(static_cast<float>(0));
                                           break;
                                       case Dtype::kFloat64:
                                           func(static_cast<double>(0));
                                           break;
                                       default:
                                           assert(0);
                                   }
                                   return list;
                               })
        .def("__add__", static_cast<Array (Array::*)(const Array&) const>(&Array::Add))
        .def("__iadd__", static_cast<Array& (Array::*)(const Array&)>(&Array::IAdd))
        .def("__mul__", static_cast<Array (Array::*)(const Array&) const>(&Array::Mul))
        .def("__imul__", static_cast<Array& (Array::*)(const Array&)>(&Array::IMul));
}

}  // namespace xchainer
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
	@brief  img メイン関係
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <iostream>
#include <tuple>
#include "img_main.hpp"
#include "core/glcore.hpp"
#include "widgets/widget_utils.hpp"
#include <boost/lexical_cast.hpp>

namespace app {

	typedef std::tuple<const std::string, const img::shared_img> save_t;

	bool save_task_(save_t t)
	{
		img::img_files imfs;
		imfs.set_image(std::get<1>(t));
		return imfs.save(std::get<0>(t));
	}

	void img_main::create_new_image_(const vtx::spos& size)
	{

	}

	void img_main::image_info_(const std::string& file, const img::i_img* img)
	{
		std::string s;
		if(!file.empty()) {
			size_t fsz = utils::get_file_size(file);
			if(fsz > 0) s = ": " + boost::lexical_cast<std::string>(fsz) + '\n';
			term_->output(s);
		}
		s = "W: " + boost::lexical_cast<std::string>(img->get_size().x) + '\n';
		term_->output(s);
		s = "H: " + boost::lexical_cast<std::string>(img->get_size().y) + '\n';
		term_->output(s);
		img::IMG::type t = img->get_type();
		if(t == img::IMG::INDEXED8) {
			term_->output("INDEXED8\n");
		} else if(t == img::IMG::FULL8) {
			term_->output("FULL8\n");
		}
		if(img->test_alpha()) {
			term_->output("Alpha\n");
		}
		s = "C: " + boost::lexical_cast<std::string>(img->count_color()) + '\n';
		term_->output(s);
		term_->output('\n');
	}

#if 0
	//-----------------------------------------------------------------//
	/*!
		@brief  初期化
	*/
	//-----------------------------------------------------------------//
	void img_main::initialize()
	{
		gl::core& core = gl::core::get_instance();

		using namespace gui;
		widget_director& wd = director_.at().widget_director_;

		{ // 画像ファイル表示用フレーム
			widget::param wp(vtx::irect(30, 30, 256, 256));
			widget_frame::param wp_;
			wp_.plate_param_.set_caption(30);
			frame_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // 画像ファイル表示イメージ
			widget::param wp(vtx::irect(0, 0, 256, 256), frame_);
			widget_image::param wp_;
			image_ = wd.add_widget<widget_image>(wp, wp_);
			image_->set_state(widget::state::CLIP_PARENTS);
			image_->set_state(widget::state::RESIZE_ROOT);
			image_->set_state(widget::state::MOVE_ROOT, false);
			image_->set_state(widget::state::POSITION_LOCK, false);
		}

		{ // 機能ツールパレット
			widget::param wp(vtx::irect(10, 10, 130, 350));
			widget_frame::param wp_;
			tools_ = wd.add_widget<widget_frame>(wp, wp_);
			tools_->set_state(widget::state::SIZE_LOCK);
		}
		{ // 新規作成ボタン
			widget::param wp(vtx::irect(10, 10+50*0, 100, 40), tools_);
			widget_button::param wp_("new");
			new_ = wd.add_widget<widget_button>(wp, wp_);
		}
		{ // ロード起動ボタン
			widget::param wp(vtx::irect(10, 10+50*1, 100, 40), tools_);
			widget_button::param wp_("load");
			load_ = wd.add_widget<widget_button>(wp, wp_);
		}
		{ // セーブ起動ボタン
			widget::param wp(vtx::irect(10, 10+50*2, 100, 40), tools_);
			widget_button::param wp_("save");
			save_ = wd.add_widget<widget_button>(wp, wp_);
		}
		short ofs = 160;
		{ // スケール FIT
			widget::param wp(vtx::irect(10, ofs+30*0, 90, 30), tools_);
			widget_radio::param wp_("fit");
			wp_.check_ = true;
			scale_fit_ = wd.add_widget<widget_radio>(wp, wp_);
		}
		{ // スケール 1X
			widget::param wp(vtx::irect(10, ofs+30*1, 90, 30), tools_);
			widget_radio::param wp_("1x");
			scale_1x_ = wd.add_widget<widget_radio>(wp, wp_);
		}
		{ // スケール 2X
			widget::param wp(vtx::irect(10, ofs+30*2, 90, 30), tools_);
			widget_radio::param wp_("2x");
			scale_2x_ = wd.add_widget<widget_radio>(wp, wp_);
		}
		{ // スケール 3X
			widget::param wp(vtx::irect(10, ofs+30*3, 90, 30), tools_);
			widget_radio::param wp_("3x");
			scale_3x_ = wd.add_widget<widget_radio>(wp, wp_);
		}
		{ // スケーラーボタン
			widget::param wp(vtx::irect(10, ofs+30*4+10, 100, 40), tools_);
			widget_button::param wp_("scale");
			scale_ = wd.add_widget<widget_button>(wp, wp_);
		}

		{ // ターミナル
			{
				widget::param wp(vtx::irect(10, 320, 9*14-8, 18*16+28));
				widget_frame::param wp_;
				wp_.plate_param_.set_caption(20);
				info_ = wd.add_widget<widget_frame>(wp, wp_);
			}
			{
				widget::param wp(vtx::irect(0), info_);
				widget_terminal::param wp_;
				wp_.echo_ = false;
				term_ = wd.add_widget<widget_terminal>(wp, wp_);
			}
		}

		{ // load ファイラー本体
			widget::param wp(vtx::irect(10, 30, 300, 200));
			widget_filer::param wp_(core.get_current_path());
			load_ctx_ = wd.add_widget<widget_filer>(wp, wp_);
			load_ctx_->enable(false);
		}
		{ // save ファイラー本体
			widget::param wp(vtx::irect(10, 30, 300, 200));
			widget_filer::param wp_(core.get_current_path());
			wp_.new_file_ = true;
			save_ctx_ = wd.add_widget<widget_filer>(wp, wp_);
			save_ctx_->enable(false);
		}
		{ // ダイアログ
			widget::param wp(vtx::irect(10, 30, 450, 200));
			widget_dialog::param wp_;
			dialog_ = wd.add_widget<widget_dialog>(wp, wp_);
			dialog_->enable(false);
		}
		{ // ダイアログ(cancel/ok)
			widget::param wp(vtx::irect(10, 30, 450, 200));
			widget_dialog::param wp_(widget_dialog::style::CANCEL_OK);
			dialog_yes_no_ = wd.add_widget<widget_dialog>(wp, wp_);
			dialog_yes_no_->enable(false);
		}
		{ // ダイアログ(scale)
			widget::param wp(vtx::irect(10, 30, 450, 200));
			widget_dialog::param wp_(widget_dialog::style::CANCEL_OK);
			dialog_scale_ = wd.add_widget<widget_dialog>(wp, wp_);
			dialog_scale_->enable(false);
		}
		{ // ダイアログ(new)
			widget::param wp(vtx::irect(10, 30, 450, 200));
			widget_dialog::param wp_(widget_dialog::style::CANCEL_OK);
			dialog_new_ = wd.add_widget<widget_dialog>(wp, wp_);
			dialog_new_->enable(false);
		}

		mobj_.initialize();

		// プリファレンスの取得
		sys::preference& pre = director_.at().preference_;
		if(load_ctx_) load_ctx_->load(pre);
		if(save_ctx_) save_ctx_->load(pre);
		if(frame_) frame_->load(pre);
		if(tools_) tools_->load(pre, false, false);
		if(scale_fit_) scale_fit_->load(pre);
		if(scale_1x_) scale_1x_->load(pre);
		if(scale_2x_) scale_2x_->load(pre);
		if(scale_3x_) scale_3x_->load(pre);
		if(info_) info_->load(pre);

		// コマンドラインの取得
		{
			auto cmds = core.get_command_path();
			for(auto s : cmds) {
				if(utils::probe_file(s)) {
					start_path_ = s;
					break;
				}
			}
		}
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  アップデート
	*/
	//-----------------------------------------------------------------//
	void img_main::update()
	{
		gl::core& core = gl::core::get_instance();

		gui::widget_director& wd = director_.at().widget_director_;

		if(new_) {
			if(new_->get_selected()) {
				img::img_rgba8* img = new img::img_rgba8;
				img->create(vtx::spos(960, 720), true);
				img->fill(img::rgba8(0, 0, 0, 0));
				src_image_ = img::shared_img(img);
				term_->output("New\n");
				image_info_("new image", src_image_.get());
				image_offset_.set(0.0f);
				frame_->at_local_param().text_param_.set_text("new image");
				mobj_.destroy();
				mobj_.initialize();
				img_handle_ = mobj_.install(src_image_.get());
				image_->at_local_param().mobj_ = mobj_;
				image_->at_local_param().mobj_handle_ = img_handle_;

///				bool f = dialog_new_->get_state(gui::widget::state::ENABLE);
///				dialog_new_->enable(!f);
			}
		}

		if(load_) {
			if(load_->get_selected()) {
				if(load_ctx_) {
					bool f = load_ctx_->get_state(gui::widget::state::ENABLE);
					load_ctx_->enable(!f);
				}
			}
		}

		if(save_) {
			if(save_->get_selected()) {
				if(save_ctx_) {
					bool f = save_ctx_->get_state(gui::widget::state::ENABLE);
					save_ctx_->enable(!f);
				}
			}
		}

		if(scale_) {
			if(scale_->get_selected()) {
				bool f = dialog_scale_->get_state(gui::widget::state::ENABLE);
				dialog_scale_->enable(!f);
			}
		}

		std::string imfn;
		// アプリ起動コマンドラインより取得のパス
		if(!start_path_.empty()) {
			imfn = start_path_;
			start_path_.clear();
		}

		// D&D 取得のパス
		int id = core.get_recv_files_id();
		if(dd_id_ != id) {
			dd_id_ = id;
			const utils::strings& ss = core.get_recv_files_path();
			if(!ss.empty()) {
				imfn = ss.back();
			}
		}

		bool load_stall = false;
		bool save_stall = false;

		if(load_ctx_) {
			if(load_ctx_->get_state(gui::widget::state::ENABLE)) {
				save_stall = true;
			}
			if(load_id_ != load_ctx_->get_select_file_id()) {
				load_id_ = load_ctx_->get_select_file_id();
				imfn = load_ctx_->get_file();
			}
		}

		if(!imfn.empty()) {
			img::img_files& imf = wd.at_img_files();
			if(!imf.load(imfn)) {
				dialog_->set_text("Can't decode image file:\n '"
								  + load_ctx_->get_file() + "'");
				dialog_->enable();
			} else {
				src_image_ = imf.get_image();
				term_->output("Ld: " + load_ctx_->get_file() + "\n");
				image_info_(load_ctx_->get_file(), src_image_.get());
				image_offset_.set(0.0f);
				frame_->at_local_param().text_param_.set_text(imfn);
				mobj_.destroy();
				mobj_.initialize();
				img_handle_ = mobj_.install(imf.get_image().get());
				image_->at_local_param().mobj_ = mobj_;
				image_->at_local_param().mobj_handle_ = img_handle_;
			}
		}

		// frame 内 image のサイズを設定
		if(frame_ && image_) {
			if(!image_->get_local_param().mobj_handle_) {
				save_stall = true;
			}

			float s = 1.0f;
			if(scale_fit_->get_check()) {
				vtx::fpos is = mobj_.get_size(img_handle_);
				vtx::fpos ss = image_->at_rect().size;
				vtx::fpos sc = ss / is;
				if(sc.x < sc.y) s = sc.x; else s = sc.y;
				image_->at_local_param().offset_ = 0.0f;
			} else {
				if(scale_1x_->get_check()) s = 1.0f;
 				else if(scale_2x_->get_check()) s = 2.0f;
 				else if(scale_3x_->get_check()) s = 3.0f;

				if(image_->get_select_in()) {
					image_offset_ = image_->get_local_param().offset_;
				}
				if(image_->get_select()) {
					vtx::spos d = image_->get_param().move_pos_ - image_->get_param().move_org_;
					image_->at_local_param().offset_ = image_offset_ + d / s;
				}
			}
			image_->at_local_param().scale_ = s;
		}

		if(save_ctx_) {
			if(save_ctx_->get_state(gui::widget::state::ENABLE)) {
				load_stall = true;
			}
			if(save_id_ != save_ctx_->get_select_file_id()) {
				save_id_ = save_ctx_->get_select_file_id();
				const std::string& fn = save_ctx_->get_file();
				if(utils::probe_file(fn)) {
					dialog_yes_no_->set_text("Over write ?:\n'"
											 + fn + "'");
					dialog_yes_no_->enable();
					save_dialog_ = true;
				} else {
					save_dialog_ = false;
				}
				save_file_name_ = fn;
			}
		}

		load_->set_state(gui::widget::state::STALL, load_stall);
		save_->set_state(gui::widget::state::STALL, save_stall);

		wd.update();

		// 画像ファイルのセーブタスク起動
		if(!save_file_name_.empty()) {
			save_t t = std::make_tuple(save_file_name_, src_image_);
			if(!save_task_(t)) {
				dialog_->set_text("Can't encode image file:\n'"
								  + save_file_name_ + "'");
				dialog_->enable();
			} else {
				term_->output("Sv");
				image_info_(save_file_name_, src_image_.get());
			}
			save_file_name_.clear();
#if 0
			if(image_saver_.valid()) {
				if(!image_saver_.get()) {
					dialog_->set_text("Can't encode image file:\n'"
									  + save_file_name_ + "'");
					dialog_->enable();
				} else {
					term_->output("Sv");
					image_info_(save_file_name_, src_image_.get());
				}
				save_file_name_.clear();
			} else {
				bool launch = false;
				if(save_dialog_) {
					if(!dialog_yes_no_->get_state(gui::widget::state::ENABLE)) {
						if(dialog_yes_no_->get_local_param().return_ok_) {
							launch = true;
						}
					}
				} else {
					launch = true;
				}
				if(launch) {
					save_t t = std::make_tuple(save_file_name_, src_image_);
					image_saver_ = std::async(std::launch::async, save_task_, t);
				}
			}
#endif
		}
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  レンダリング
	*/
	//-----------------------------------------------------------------//
	void img_main::render()
	{
		director_.at().widget_director_.service();
		director_.at().widget_director_.render();
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  廃棄
	*/
	//-----------------------------------------------------------------//
	void img_main::destroy()
	{
		sys::preference& pre = director_.at().preference_;
		if(load_ctx_) load_ctx_->save(pre);
		if(save_ctx_) save_ctx_->save(pre);
		if(frame_) frame_->save(pre);
		if(tools_) tools_->save(pre);
		if(scale_fit_) scale_fit_->save(pre);
		if(scale_1x_) scale_1x_->save(pre);
		if(scale_2x_) scale_2x_->save(pre);
		if(scale_3x_) scale_3x_->save(pre);
		if(info_) info_->save(pre);
	}
#endif
}
<commit_msg>Update: to header<commit_after><|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Till Adam <adam@kde.org>                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library 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 Library 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 "akonadi.h"
#include "akonadiconnection.h"
#include "serveradaptor.h"
#include "akdebug.h"

#include "cachecleaner.h"
#include "intervalcheck.h"
#include "storage/dbconfig.h"
#include "storage/datastore.h"
#include "notificationmanager.h"
#include "resourcemanager.h"
#include "tracer.h"
#include "xesammanager.h"
#include "nepomukmanager.h"
#include "debuginterface.h"
#include "storage/itemretrievalthread.h"

#include "libs/xdgbasedirs_p.h"
#include "libs/protocol_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtCore/QSettings>
#include <QtCore/QTimer>

#include <config-akonadi.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>

using namespace Akonadi;

static AkonadiServer *s_instance = 0;

AkonadiServer::AkonadiServer( QObject* parent )
    : QLocalServer( parent )
    , mCacheCleaner( 0 )
    , mIntervalChecker( 0 )
    , mItemRetrievalThread( 0 )
    , mDatabaseProcess( 0 )
    , mAlreadyShutdown( false )
{
    DbConfig::init();
    startDatabaseProcess();

    s_instance = this;

    const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
    QSettings settings( serverConfigFile, QSettings::IniFormat );

    const QString connectionSettingsFile = XdgBaseDirs::akonadiConnectionConfigFile( XdgBaseDirs::WriteOnly );
    QSettings connectionSettings( connectionSettingsFile, QSettings::IniFormat );

#ifdef Q_OS_WIN
    QString namedPipe = settings.value( QLatin1String( "Connection/NamedPipe" ), QLatin1String( "Akonadi" ) ).toString();
    if ( !listen( namedPipe ) )
      akFatal() << "Unable to listen on Named Pipe" << namedPipe;

    connectionSettings.setValue( QLatin1String( "Data/Method" ), QLatin1String( "NamedPipe" ) );
    connectionSettings.setValue( QLatin1String( "Data/NamedPipe" ), namedPipe );
#else
    const QString defaultSocketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) );
    QString socketDir = settings.value( QLatin1String( "Connection/SocketDirectory" ), defaultSocketDir ).toString();
    if ( socketDir[0] != QLatin1Char( '/' ) ) {
      QDir::home().mkdir( socketDir );
      socketDir = QDir::homePath() + QLatin1Char( '/' ) + socketDir;
    }

    const QString socketFile = socketDir + QLatin1String( "/akonadiserver.socket" );
    unlink( socketFile.toUtf8().constData() );
    if ( !listen( socketFile ) )
      akFatal() << "Unable to listen on Unix socket" << socketFile;

    connectionSettings.setValue( QLatin1String( "Data/Method" ), QLatin1String( "UnixPath" ) );
    connectionSettings.setValue( QLatin1String( "Data/UnixPath" ), socketFile );
#endif

    // initialize the database
    DataStore *db = DataStore::self();
    if ( !db->database().isOpen() )
      akFatal() << "Unable to open database" << db->database().lastError().text();
    if ( !db->init() )
      akFatal() << "Unable to initialize database.";

    NotificationManager::self();
    Tracer::self();
    new DebugInterface( this );
    ResourceManager::self();
    if ( settings.value( QLatin1String( "Cache/EnableCleaner" ), true ).toBool() ) {
      mCacheCleaner = new CacheCleaner( this );
      mCacheCleaner->start( QThread::IdlePriority );
    }

    mIntervalChecker = new IntervalCheck( this );
    mIntervalChecker->start( QThread::IdlePriority );

    mItemRetrievalThread = new ItemRetrievalThread( this );
    mItemRetrievalThread->start( QThread::HighPriority );

    mSearchManager = new NepomukManager( this );

    new ServerAdaptor( this );
    QDBusConnection::sessionBus().registerObject( QLatin1String( "/Server" ), this );

    const QByteArray dbusAddress = qgetenv( "DBUS_SESSION_BUS_ADDRESS" );
    if ( !dbusAddress.isEmpty() ) {
      connectionSettings.setValue( QLatin1String( "DBUS/Address" ), QLatin1String( dbusAddress ) );
    }

    connect( QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
             SLOT(serviceOwnerChanged(QString,QString,QString)) );
}

AkonadiServer::~AkonadiServer()
{
}

template <typename T> static void quitThread( T & thread )
{
  if ( !thread )
    return;
  thread->quit();
  thread->wait();
  delete thread;
  thread = 0;
}

void AkonadiServer::quit()
{
    if ( mAlreadyShutdown )
      return;
    mAlreadyShutdown = true;

    qDebug() << "terminating service threads";
    quitThread( mCacheCleaner );
    quitThread( mIntervalChecker );
    quitThread( mItemRetrievalThread );

    delete mSearchManager;
    mSearchManager = 0;

    qDebug() << "terminating connection threads";
    for ( int i = 0; i < mConnections.count(); ++i )
      quitThread( mConnections[ i ] );
    mConnections.clear();

    DataStore::self()->close();
    Q_ASSERT( QSqlDatabase::connectionNames().isEmpty() );

    qDebug() << "stopping db process";
    stopDatabaseProcess();

    QSettings settings( XdgBaseDirs::akonadiServerConfigFile(), QSettings::IniFormat );
    const QString connectionSettingsFile = XdgBaseDirs::akonadiConnectionConfigFile( XdgBaseDirs::WriteOnly );

#ifndef Q_OS_WIN
    QSettings connectionSettings( connectionSettingsFile, QSettings::IniFormat );
    const QString defaultSocketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) );
    const QString socketDir = settings.value( QLatin1String( "Connection/SocketDirectory" ), defaultSocketDir ).toString();

    if ( !QDir::home().remove( socketDir + QLatin1String( "/akonadiserver.socket" ) ) )
        akError() << "Failed to remove Unix socket";
#endif
    if ( !QDir::home().remove( connectionSettingsFile ) )
        akError() << "Failed to remove runtime connection config file";

    QTimer::singleShot( 0, this, SLOT( doQuit() ) );
}

void AkonadiServer::doQuit()
{
    QCoreApplication::exit();
}

void AkonadiServer::incomingConnection( quintptr socketDescriptor )
{
    if ( mAlreadyShutdown )
      return;
    QPointer<AkonadiConnection> thread = new AkonadiConnection( socketDescriptor, this );
    connect( thread, SIGNAL( finished() ), thread, SLOT( deleteLater() ) );
    mConnections.append( thread );
    thread->start();
}

AkonadiServer * AkonadiServer::instance()
{
    if ( !s_instance )
        s_instance = new AkonadiServer();
    return s_instance;
}

void AkonadiServer::startDatabaseProcess()
{
  if ( !DbConfig::useInternalServer() )
    return;

  const QString mysqldPath = DbConfig::serverPath();
  if ( mysqldPath.isEmpty() )
    akFatal() << "No path to mysqld set in server configuration!";

  // create the database directories if they don't exists
  const QString dataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) );
  const QString akDir   = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/" ) );
  const QString miscDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) );
  const QString fileDataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/file_db_data" ) );

  // generate config file
  const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
  const QString localConfig  = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-local.conf" ) );
  const QString actualConfig = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1String("/mysql.conf");
  if ( globalConfig.isEmpty() )
    akFatal() << "Did not find MySQL server default configuration (mysql-global.conf)";
  bool confUpdate = false;
  QFile actualFile ( actualConfig );
  // update conf only if either global (or local) is newer than actual
  if ( (QFileInfo( globalConfig ).lastModified() > QFileInfo( actualFile ).lastModified()) ||
       (QFileInfo( localConfig ).lastModified()  > QFileInfo( actualFile ).lastModified()) )
  {
    QFile globalFile( globalConfig );
    QFile localFile ( localConfig );
    if ( globalFile.open( QFile::ReadOnly ) && actualFile.open( QFile::WriteOnly ) ) {
      actualFile.write( globalFile.readAll() );
      if ( !localConfig.isEmpty() ) {
        if ( localFile.open( QFile::ReadOnly ) ) {
          actualFile.write( localFile.readAll() );
          localFile.close();
        }
      }
      globalFile.close();
      actualFile.close();
      confUpdate = true;
    } else {
      akError() << "Unable to create MySQL server configuration file.";
      akError() << "This means that either the default configuration file (mysql-global.conf) was not readable";
      akFatal() << "or the target file (mysql.conf) could not be written.";
    }
  }

  // MySQL doesn't like world writeable config files (which makes sense), but
  // our config file somehow ends up being world-writable on some systems for no
  // apparent reason nevertheless, so fix that
  const QFile::Permissions allowedPerms = actualFile.permissions()
      & ( QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::WriteGroup | QFile::ReadOther );
  if ( allowedPerms != actualFile.permissions() )
    actualFile.setPermissions( allowedPerms );

  if ( dataDir.isEmpty() )
    akFatal() << "Akonadi server was not able not create database data directory";

  if ( akDir.isEmpty() )
    akFatal() << "Akonadi server was not able not create database log directory";

  if ( miscDir.isEmpty() )
    akFatal() << "Akonadi server was not able not create database misc directory";

  // move mysql error log file out of the way
  const QFileInfo errorLog( dataDir + QDir::separator() + QString::fromLatin1( "mysql.err" ) );
  if ( errorLog.exists() ) {
    QFile logFile( errorLog.absoluteFilePath() );
    QFile oldLogFile( dataDir + QDir::separator() + QString::fromLatin1( "mysql.err.old" ) );
    if ( logFile.open( QFile::ReadOnly ) && oldLogFile.open( QFile::Append ) ) {
      oldLogFile.write( logFile.readAll() );
      oldLogFile.close();
      logFile.close();
      logFile.remove();
    } else {
      akError() << "Failed to open MySQL error log.";
    }
  }

  // clear mysql ib_logfile's in case innodb_log_file_size option changed in last confUpdate
  if ( confUpdate ) {
      QFile(dataDir + QDir::separator() + QString::fromLatin1( "ib_logfile0" )).remove();
      QFile(dataDir + QDir::separator() + QString::fromLatin1( "ib_logfile1" )).remove();
  }

  // synthesize the mysqld command
  QStringList arguments;
  arguments << QString::fromLatin1( "--defaults-file=%1/mysql.conf" ).arg( akDir );
  arguments << QString::fromLatin1( "--datadir=%1/" ).arg( dataDir );
  arguments << QString::fromLatin1( "--socket=%1/mysql.socket" ).arg( miscDir );

  mDatabaseProcess = new QProcess( this );
  mDatabaseProcess->start( mysqldPath, arguments );
  if ( !mDatabaseProcess->waitForStarted() ) {
    akError() << "Could not start database server!";
    akError() << "executable:" << mysqldPath;
    akError() << "arguments:" << arguments;
    akFatal() << "process error:" << mDatabaseProcess->errorString();
  }

  const QLatin1String initCon( "initConnection" );
  {
    QSqlDatabase db = QSqlDatabase::addDatabase( DbConfig::driverName(), initCon );
    DbConfig::configure( db );
    db.setDatabaseName( QString() ); // might not exist yet, then connecting to the actual db will fail
    if ( !db.isValid() )
      akFatal() << "Invalid database object during database server startup";

    bool opened = false;
    for ( int i = 0; i < 120; ++i ) {
      opened = db.open();
      if ( opened )
        break;
      if ( mDatabaseProcess->waitForFinished( 500 ) ) {
        akError() << "Database process exited unexpectedly during initial connection!";
        akError() << "executable:" << mysqldPath;
        akError() << "arguments:" << arguments;
        akError() << "stdout:" << mDatabaseProcess->readAllStandardOutput();
        akError() << "stderr:" << mDatabaseProcess->readAllStandardError();
        akError() << "exit code:" << mDatabaseProcess->exitCode();
        akFatal() << "process error:" << mDatabaseProcess->errorString();
      }
    }

    if ( opened ) {
      {
        QSqlQuery query( db );
        if ( !query.exec( QString::fromLatin1( "USE %1" ).arg( DbConfig::databaseName() ) ) ) {
          akDebug() << "Failed to use database" << DbConfig::databaseName();
          akDebug() << "Query error:" << query.lastError().text();
          akDebug() << "Database error:" << db.lastError().text();
          akDebug() << "Trying to create database now...";
          if ( !query.exec( QLatin1String( "CREATE DATABASE akonadi" ) ) ) {
            akError() << "Failed to create database";
            akError() << "Query error:" << query.lastError().text();
            akFatal() << "Database error:" << db.lastError().text();
          }
        }
      } // make sure query is destroyed before we close the db
      db.close();
    }
  }

  QSqlDatabase::removeDatabase( initCon );
}

void AkonadiServer::stopDatabaseProcess()
{
  if ( !mDatabaseProcess )
    return;
  mDatabaseProcess->terminate();
  mDatabaseProcess->waitForFinished();
}

void AkonadiServer::serviceOwnerChanged(const QString & name, const QString & oldOwner, const QString & newOwner)
{
  Q_UNUSED( oldOwner );
  if ( name == QLatin1String( AKONADI_DBUS_CONTROL_SERVICE ) && newOwner.isEmpty() ) {
    akError() << "Control process died, committing suicide!";
    quit();
  }
}

#include "akonadi.moc"
<commit_msg>Allow to enable the dummy search manager again, for testing. At least until I find a way to get Nepomuk running in the test environment.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Till Adam <adam@kde.org>                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library 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 Library 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 "akonadi.h"
#include "akonadiconnection.h"
#include "serveradaptor.h"
#include "akdebug.h"

#include "cachecleaner.h"
#include "intervalcheck.h"
#include "storage/dbconfig.h"
#include "storage/datastore.h"
#include "notificationmanager.h"
#include "resourcemanager.h"
#include "tracer.h"
#include "xesammanager.h"
#include "nepomukmanager.h"
#include "debuginterface.h"
#include "storage/itemretrievalthread.h"

#include "libs/xdgbasedirs_p.h"
#include "libs/protocol_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtCore/QSettings>
#include <QtCore/QTimer>

#include <config-akonadi.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>

using namespace Akonadi;

static AkonadiServer *s_instance = 0;

AkonadiServer::AkonadiServer( QObject* parent )
    : QLocalServer( parent )
    , mCacheCleaner( 0 )
    , mIntervalChecker( 0 )
    , mItemRetrievalThread( 0 )
    , mDatabaseProcess( 0 )
    , mAlreadyShutdown( false )
{
    DbConfig::init();
    startDatabaseProcess();

    s_instance = this;

    const QString serverConfigFile = XdgBaseDirs::akonadiServerConfigFile( XdgBaseDirs::ReadWrite );
    QSettings settings( serverConfigFile, QSettings::IniFormat );

    const QString connectionSettingsFile = XdgBaseDirs::akonadiConnectionConfigFile( XdgBaseDirs::WriteOnly );
    QSettings connectionSettings( connectionSettingsFile, QSettings::IniFormat );

#ifdef Q_OS_WIN
    QString namedPipe = settings.value( QLatin1String( "Connection/NamedPipe" ), QLatin1String( "Akonadi" ) ).toString();
    if ( !listen( namedPipe ) )
      akFatal() << "Unable to listen on Named Pipe" << namedPipe;

    connectionSettings.setValue( QLatin1String( "Data/Method" ), QLatin1String( "NamedPipe" ) );
    connectionSettings.setValue( QLatin1String( "Data/NamedPipe" ), namedPipe );
#else
    const QString defaultSocketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) );
    QString socketDir = settings.value( QLatin1String( "Connection/SocketDirectory" ), defaultSocketDir ).toString();
    if ( socketDir[0] != QLatin1Char( '/' ) ) {
      QDir::home().mkdir( socketDir );
      socketDir = QDir::homePath() + QLatin1Char( '/' ) + socketDir;
    }

    const QString socketFile = socketDir + QLatin1String( "/akonadiserver.socket" );
    unlink( socketFile.toUtf8().constData() );
    if ( !listen( socketFile ) )
      akFatal() << "Unable to listen on Unix socket" << socketFile;

    connectionSettings.setValue( QLatin1String( "Data/Method" ), QLatin1String( "UnixPath" ) );
    connectionSettings.setValue( QLatin1String( "Data/UnixPath" ), socketFile );
#endif

    // initialize the database
    DataStore *db = DataStore::self();
    if ( !db->database().isOpen() )
      akFatal() << "Unable to open database" << db->database().lastError().text();
    if ( !db->init() )
      akFatal() << "Unable to initialize database.";

    NotificationManager::self();
    Tracer::self();
    new DebugInterface( this );
    ResourceManager::self();
    if ( settings.value( QLatin1String( "Cache/EnableCleaner" ), true ).toBool() ) {
      mCacheCleaner = new CacheCleaner( this );
      mCacheCleaner->start( QThread::IdlePriority );
    }

    mIntervalChecker = new IntervalCheck( this );
    mIntervalChecker->start( QThread::IdlePriority );

    mItemRetrievalThread = new ItemRetrievalThread( this );
    mItemRetrievalThread->start( QThread::HighPriority );

    const QString searchManager = settings.value( QLatin1String( "Search/Manager" ), QLatin1String( "Nepomuk" ) ).toString();
    if ( searchManager == QLatin1String( "Nepomuk" ) )
      mSearchManager = new NepomukManager( this );
    else
      mSearchManager = new DummySearchManager;

    new ServerAdaptor( this );
    QDBusConnection::sessionBus().registerObject( QLatin1String( "/Server" ), this );

    const QByteArray dbusAddress = qgetenv( "DBUS_SESSION_BUS_ADDRESS" );
    if ( !dbusAddress.isEmpty() ) {
      connectionSettings.setValue( QLatin1String( "DBUS/Address" ), QLatin1String( dbusAddress ) );
    }

    connect( QDBusConnection::sessionBus().interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)),
             SLOT(serviceOwnerChanged(QString,QString,QString)) );
}

AkonadiServer::~AkonadiServer()
{
}

template <typename T> static void quitThread( T & thread )
{
  if ( !thread )
    return;
  thread->quit();
  thread->wait();
  delete thread;
  thread = 0;
}

void AkonadiServer::quit()
{
    if ( mAlreadyShutdown )
      return;
    mAlreadyShutdown = true;

    qDebug() << "terminating service threads";
    quitThread( mCacheCleaner );
    quitThread( mIntervalChecker );
    quitThread( mItemRetrievalThread );

    delete mSearchManager;
    mSearchManager = 0;

    qDebug() << "terminating connection threads";
    for ( int i = 0; i < mConnections.count(); ++i )
      quitThread( mConnections[ i ] );
    mConnections.clear();

    DataStore::self()->close();
    Q_ASSERT( QSqlDatabase::connectionNames().isEmpty() );

    qDebug() << "stopping db process";
    stopDatabaseProcess();

    QSettings settings( XdgBaseDirs::akonadiServerConfigFile(), QSettings::IniFormat );
    const QString connectionSettingsFile = XdgBaseDirs::akonadiConnectionConfigFile( XdgBaseDirs::WriteOnly );

#ifndef Q_OS_WIN
    QSettings connectionSettings( connectionSettingsFile, QSettings::IniFormat );
    const QString defaultSocketDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) );
    const QString socketDir = settings.value( QLatin1String( "Connection/SocketDirectory" ), defaultSocketDir ).toString();

    if ( !QDir::home().remove( socketDir + QLatin1String( "/akonadiserver.socket" ) ) )
        akError() << "Failed to remove Unix socket";
#endif
    if ( !QDir::home().remove( connectionSettingsFile ) )
        akError() << "Failed to remove runtime connection config file";

    QTimer::singleShot( 0, this, SLOT( doQuit() ) );
}

void AkonadiServer::doQuit()
{
    QCoreApplication::exit();
}

void AkonadiServer::incomingConnection( quintptr socketDescriptor )
{
    if ( mAlreadyShutdown )
      return;
    QPointer<AkonadiConnection> thread = new AkonadiConnection( socketDescriptor, this );
    connect( thread, SIGNAL( finished() ), thread, SLOT( deleteLater() ) );
    mConnections.append( thread );
    thread->start();
}

AkonadiServer * AkonadiServer::instance()
{
    if ( !s_instance )
        s_instance = new AkonadiServer();
    return s_instance;
}

void AkonadiServer::startDatabaseProcess()
{
  if ( !DbConfig::useInternalServer() )
    return;

  const QString mysqldPath = DbConfig::serverPath();
  if ( mysqldPath.isEmpty() )
    akFatal() << "No path to mysqld set in server configuration!";

  // create the database directories if they don't exists
  const QString dataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_data" ) );
  const QString akDir   = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/" ) );
  const QString miscDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/db_misc" ) );
  const QString fileDataDir = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi/file_db_data" ) );

  // generate config file
  const QString globalConfig = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-global.conf" ) );
  const QString localConfig  = XdgBaseDirs::findResourceFile( "config", QLatin1String( "akonadi/mysql-local.conf" ) );
  const QString actualConfig = XdgBaseDirs::saveDir( "data", QLatin1String( "akonadi" ) ) + QLatin1String("/mysql.conf");
  if ( globalConfig.isEmpty() )
    akFatal() << "Did not find MySQL server default configuration (mysql-global.conf)";
  bool confUpdate = false;
  QFile actualFile ( actualConfig );
  // update conf only if either global (or local) is newer than actual
  if ( (QFileInfo( globalConfig ).lastModified() > QFileInfo( actualFile ).lastModified()) ||
       (QFileInfo( localConfig ).lastModified()  > QFileInfo( actualFile ).lastModified()) )
  {
    QFile globalFile( globalConfig );
    QFile localFile ( localConfig );
    if ( globalFile.open( QFile::ReadOnly ) && actualFile.open( QFile::WriteOnly ) ) {
      actualFile.write( globalFile.readAll() );
      if ( !localConfig.isEmpty() ) {
        if ( localFile.open( QFile::ReadOnly ) ) {
          actualFile.write( localFile.readAll() );
          localFile.close();
        }
      }
      globalFile.close();
      actualFile.close();
      confUpdate = true;
    } else {
      akError() << "Unable to create MySQL server configuration file.";
      akError() << "This means that either the default configuration file (mysql-global.conf) was not readable";
      akFatal() << "or the target file (mysql.conf) could not be written.";
    }
  }

  // MySQL doesn't like world writeable config files (which makes sense), but
  // our config file somehow ends up being world-writable on some systems for no
  // apparent reason nevertheless, so fix that
  const QFile::Permissions allowedPerms = actualFile.permissions()
      & ( QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::WriteGroup | QFile::ReadOther );
  if ( allowedPerms != actualFile.permissions() )
    actualFile.setPermissions( allowedPerms );

  if ( dataDir.isEmpty() )
    akFatal() << "Akonadi server was not able not create database data directory";

  if ( akDir.isEmpty() )
    akFatal() << "Akonadi server was not able not create database log directory";

  if ( miscDir.isEmpty() )
    akFatal() << "Akonadi server was not able not create database misc directory";

  // move mysql error log file out of the way
  const QFileInfo errorLog( dataDir + QDir::separator() + QString::fromLatin1( "mysql.err" ) );
  if ( errorLog.exists() ) {
    QFile logFile( errorLog.absoluteFilePath() );
    QFile oldLogFile( dataDir + QDir::separator() + QString::fromLatin1( "mysql.err.old" ) );
    if ( logFile.open( QFile::ReadOnly ) && oldLogFile.open( QFile::Append ) ) {
      oldLogFile.write( logFile.readAll() );
      oldLogFile.close();
      logFile.close();
      logFile.remove();
    } else {
      akError() << "Failed to open MySQL error log.";
    }
  }

  // clear mysql ib_logfile's in case innodb_log_file_size option changed in last confUpdate
  if ( confUpdate ) {
      QFile(dataDir + QDir::separator() + QString::fromLatin1( "ib_logfile0" )).remove();
      QFile(dataDir + QDir::separator() + QString::fromLatin1( "ib_logfile1" )).remove();
  }

  // synthesize the mysqld command
  QStringList arguments;
  arguments << QString::fromLatin1( "--defaults-file=%1/mysql.conf" ).arg( akDir );
  arguments << QString::fromLatin1( "--datadir=%1/" ).arg( dataDir );
  arguments << QString::fromLatin1( "--socket=%1/mysql.socket" ).arg( miscDir );

  mDatabaseProcess = new QProcess( this );
  mDatabaseProcess->start( mysqldPath, arguments );
  if ( !mDatabaseProcess->waitForStarted() ) {
    akError() << "Could not start database server!";
    akError() << "executable:" << mysqldPath;
    akError() << "arguments:" << arguments;
    akFatal() << "process error:" << mDatabaseProcess->errorString();
  }

  const QLatin1String initCon( "initConnection" );
  {
    QSqlDatabase db = QSqlDatabase::addDatabase( DbConfig::driverName(), initCon );
    DbConfig::configure( db );
    db.setDatabaseName( QString() ); // might not exist yet, then connecting to the actual db will fail
    if ( !db.isValid() )
      akFatal() << "Invalid database object during database server startup";

    bool opened = false;
    for ( int i = 0; i < 120; ++i ) {
      opened = db.open();
      if ( opened )
        break;
      if ( mDatabaseProcess->waitForFinished( 500 ) ) {
        akError() << "Database process exited unexpectedly during initial connection!";
        akError() << "executable:" << mysqldPath;
        akError() << "arguments:" << arguments;
        akError() << "stdout:" << mDatabaseProcess->readAllStandardOutput();
        akError() << "stderr:" << mDatabaseProcess->readAllStandardError();
        akError() << "exit code:" << mDatabaseProcess->exitCode();
        akFatal() << "process error:" << mDatabaseProcess->errorString();
      }
    }

    if ( opened ) {
      {
        QSqlQuery query( db );
        if ( !query.exec( QString::fromLatin1( "USE %1" ).arg( DbConfig::databaseName() ) ) ) {
          akDebug() << "Failed to use database" << DbConfig::databaseName();
          akDebug() << "Query error:" << query.lastError().text();
          akDebug() << "Database error:" << db.lastError().text();
          akDebug() << "Trying to create database now...";
          if ( !query.exec( QLatin1String( "CREATE DATABASE akonadi" ) ) ) {
            akError() << "Failed to create database";
            akError() << "Query error:" << query.lastError().text();
            akFatal() << "Database error:" << db.lastError().text();
          }
        }
      } // make sure query is destroyed before we close the db
      db.close();
    }
  }

  QSqlDatabase::removeDatabase( initCon );
}

void AkonadiServer::stopDatabaseProcess()
{
  if ( !mDatabaseProcess )
    return;
  mDatabaseProcess->terminate();
  mDatabaseProcess->waitForFinished();
}

void AkonadiServer::serviceOwnerChanged(const QString & name, const QString & oldOwner, const QString & newOwner)
{
  Q_UNUSED( oldOwner );
  if ( name == QLatin1String( AKONADI_DBUS_CONTROL_SERVICE ) && newOwner.isEmpty() ) {
    akError() << "Control process died, committing suicide!";
    quit();
  }
}

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


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "protocol.h"

#include "chainparams.h"
#include "util.h"
#include "utilstrencodings.h"

#ifndef WIN32
# include <arpa/inet.h>
#endif

static const char* ppszTypeName[] =
{
    "ERROR",
    "tx",
    "block",
    "filtered block",
    "tx lock request",
    "tx lock vote",
    "spork",
    "masternode winner",
    "masternode scan",
    "masternode vote",
    "masternode proposal",
    "masternode quorum",
    "masternode announce",
    "masternode ping",
    "unknown",
    "unknown",
    "unknown",
    "unknown",
    "unknown",
    "unknown"
};

CMessageHeader::CMessageHeader()
{
    memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE);
    memset(pchCommand, 0, sizeof(pchCommand));
    nMessageSize = -1;
    nChecksum = 0;
}

CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
{
    memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE);
    memset(pchCommand, 0, sizeof(pchCommand));
    strncpy(pchCommand, pszCommand, COMMAND_SIZE);
    nMessageSize = nMessageSizeIn;
    nChecksum = 0;
}

std::string CMessageHeader::GetCommand() const
{
    return std::string(pchCommand, pchCommand + strnlen_int(pchCommand, COMMAND_SIZE));
}

bool CMessageHeader::IsValid() const
{
    // Check start string
    if (memcmp(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0)
        return false;

    // Check the command string for errors
    for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
    {
        if (*p1 == 0)
        {
            // Must be all zeros after the first zero
            for (; p1 < pchCommand + COMMAND_SIZE; p1++)
                if (*p1 != 0)
                    return false;
        }
        else if (*p1 < ' ' || *p1 > 0x7E)
            return false;
    }

    // Message size
    if (nMessageSize > MAX_SIZE)
    {
        LogPrintf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand(), nMessageSize);
        return false;
    }

    return true;
}

CAddress::CAddress() : CService()
{
    Init();
}

CAddress::CAddress(CService ipIn, uint64_t nServicesIn) : CService(ipIn)
{
    Init();
    nServices = nServicesIn;
}

void CAddress::Init()
{
    nServices = NODE_NETWORK;
    nTime = 100000000;
    nLastTry = 0;
}

CInv::CInv()
{
    type = 0;
    hash = 0;
}

CInv::CInv(int typeIn, const uint256& hashIn)
{
    type = typeIn;
    hash = hashIn;
}

CInv::CInv(const std::string& strType, const uint256& hashIn)
{
    unsigned int i;
    for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
    {
        if (strType == ppszTypeName[i])
        {
            type = i;
            break;
        }
    }
    if (i == ARRAYLEN(ppszTypeName))
        throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType));
    hash = hashIn;
}

bool operator<(const CInv& a, const CInv& b)
{
    return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
}

bool CInv::IsKnownType() const
{
    return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName));
}

const char* CInv::GetCommand() const
{
    if (!IsKnownType())
        throw std::out_of_range(strprintf("CInv::GetCommand() : type=%d unknown type", type));
    return ppszTypeName[type];
}

std::string CInv::ToString() const
{
    return strprintf("%s %s", GetCommand(), hash.ToString());
}
<commit_msg>Few inv related fixes: - add missing strings and make inv strings a bit more consistent (imo) - remove "unknown" types that were used to prevent errors thrown at user with old wallet,   just log such errors in debug mode for "net" category. Should also make behaviour of functions   relaing on CInv::IsKnownType() more adequate   (and it doesn't make sense to warn users by throwing errors at them in such situations anyway I guess)<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "protocol.h"

#include "chainparams.h"
#include "util.h"
#include "utilstrencodings.h"

#ifndef WIN32
# include <arpa/inet.h>
#endif

static const char* ppszTypeName[] =
{
    "ERROR",
    "tx",
    "block",
    "filtered block",
    "tx lock request",
    "tx lock vote",
    "spork",
    "mn winner",
    "mn scan error",
    "mn budget vote",
    "mn budget proposal",
    "mn budget finalized",
    "mn budget finalized vote",
    "mn quorum",
    "mn announce",
    "mn ping"
};

CMessageHeader::CMessageHeader()
{
    memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE);
    memset(pchCommand, 0, sizeof(pchCommand));
    nMessageSize = -1;
    nChecksum = 0;
}

CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
{
    memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE);
    memset(pchCommand, 0, sizeof(pchCommand));
    strncpy(pchCommand, pszCommand, COMMAND_SIZE);
    nMessageSize = nMessageSizeIn;
    nChecksum = 0;
}

std::string CMessageHeader::GetCommand() const
{
    return std::string(pchCommand, pchCommand + strnlen_int(pchCommand, COMMAND_SIZE));
}

bool CMessageHeader::IsValid() const
{
    // Check start string
    if (memcmp(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE) != 0)
        return false;

    // Check the command string for errors
    for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
    {
        if (*p1 == 0)
        {
            // Must be all zeros after the first zero
            for (; p1 < pchCommand + COMMAND_SIZE; p1++)
                if (*p1 != 0)
                    return false;
        }
        else if (*p1 < ' ' || *p1 > 0x7E)
            return false;
    }

    // Message size
    if (nMessageSize > MAX_SIZE)
    {
        LogPrintf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand(), nMessageSize);
        return false;
    }

    return true;
}

CAddress::CAddress() : CService()
{
    Init();
}

CAddress::CAddress(CService ipIn, uint64_t nServicesIn) : CService(ipIn)
{
    Init();
    nServices = nServicesIn;
}

void CAddress::Init()
{
    nServices = NODE_NETWORK;
    nTime = 100000000;
    nLastTry = 0;
}

CInv::CInv()
{
    type = 0;
    hash = 0;
}

CInv::CInv(int typeIn, const uint256& hashIn)
{
    type = typeIn;
    hash = hashIn;
}

CInv::CInv(const std::string& strType, const uint256& hashIn)
{
    unsigned int i;
    for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
    {
        if (strType == ppszTypeName[i])
        {
            type = i;
            break;
        }
    }
    if (i == ARRAYLEN(ppszTypeName))
        LogPrint("net", "CInv::CInv(string, uint256) : unknown type '%s'", strType);
    hash = hashIn;
}

bool operator<(const CInv& a, const CInv& b)
{
    return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
}

bool CInv::IsKnownType() const
{
    return (type >= 1 && type < (int)ARRAYLEN(ppszTypeName));
}

const char* CInv::GetCommand() const
{
    if (!IsKnownType())
        LogPrint("net", "CInv::GetCommand() : type=%d unknown type", type);

    return ppszTypeName[type];
}

std::string CInv::ToString() const
{
    return strprintf("%s %s", GetCommand(), hash.ToString());
}
<|endoftext|>


<commit_before>#include <iostream>
#include <Poco/Logger.h>
#include <Poco/Message.h>
#include <Poco/File.h>
#include <Poco/Util/Option.h>
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/HelpFormatter.h>
#include <Poco/Util/ServerApplication.h>

#include "server/MongooseServer.h"
#include "di/DependencyInjector.h"
#include "UIServerModule.h"

using namespace std;
using namespace Poco;
using namespace Poco::Util;
using namespace BeeeOn;

#define DEFAULT_PORT 8000

#define SYSTEM_LOGGING_FILE "/etc/beeeon/ui-server/logging.ini"
#define SYSTEM_CONFIG_FILE "/etc/beeeon/ui-server/server.ini"
#define SYSTEM_SERVICES_FILE "/etc/beeeon/ui-server/services.xml"

static Option optConfig("config", "c",
		"general configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optServices("services", "s",
		"services configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optLogging("logging", "l",
		"logging configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optLogLevel("log-level", "L",
		"change startup log-level (trace, debug, [info],"
		" notice, warn, error, fatal, trace)",
		false,
		"<level>",
		true);
static Option optPort("port", "p",
		"server port to listen on",
		false,
		"<port>",
		true);
static Option optHelp("help", "h", "print help");

class Startup : public ServerApplication {
public:
	Startup():
		m_printHelp(false),
		m_serverPort(DEFAULT_PORT)
	{
	}

protected:
	/**
	 * Extend log-level parsing by shortcuts: info, warn, err, cirt.
	 */
	int parseLogLevel(const string &level)
	{
		if (icompare(level, "info") == 0)
			return Message::PRIO_INFORMATION;
		if (icompare(level, "warn") == 0)
			return Message::PRIO_WARNING;
		if (icompare(level, "err") == 0)
			return Message::PRIO_ERROR;
		if (icompare(level, "crit") == 0)
			return Message::PRIO_CRITICAL;

		return Logger::parseLevel(level);
	}

	void handleOption(const string &name, const string &value)
	{
		if (name == "services")
			m_userServices = value;
		if (name == "logging")
			m_userLogging = value;
		if (name == "config")
			m_userConfig = value;
		if (name == "help")
			m_printHelp = true;
		if (name == "log-level")
			logger().setLevel(parseLogLevel(value));
		if (name == "port")
			m_serverPort = stoi(value);

		Application::handleOption(name, value);
	}

	void loadAllConfiguration()
	{
		findAndLoadConfig();
		findAndLoadLogging();
		findAndLoadServices();
	}

	string parentPath(const File &file)
	{
		Path path(file.path());
		return path.parent().toString();
	}

	bool readConfiguration(const File &file)
	{
		if (!file.exists()) {
			logger().debug("configuration file "
					+ file.path() + " not found");
			return false;
		}

		loadConfiguration(file.path());
		logger().notice("configuration file "
				+ file.path() + " loaded");
		return true;
	}

	void findAndLoadConfig()
	{
		File user(m_userConfig);
		File system(SYSTEM_CONFIG_FILE);

		config().setString("config.dir",
			config().getString("application.dir"));

		if (!m_userConfig.empty() && readConfiguration(user))
			config().setString("config.dir", parentPath(user));
		else if (readConfiguration(system))
			config().setString("config.dir", parentPath(system));
		else
			logger().warning("no main configration found");
	}

	void findAndLoadLogging()
	{
		File user(m_userLogging);
		File system(config().getString(
				"ui.config.logging", SYSTEM_LOGGING_FILE));

		if (!m_userLogging.empty() && readConfiguration(user))
			return;
		else if (!readConfiguration(system.path()))
			logger().warning("no logging configuration found");
	}

	void findAndLoadServices()
	{
		File user(m_userServices);
		File system(config().getString(
				"ui.config.services", SYSTEM_SERVICES_FILE));

		if (!m_userServices.empty() && readConfiguration(user))
			return;
		else if (!readConfiguration(system))
			logger().warning("no services configuration found");
	}

	void initialize(Application &app)
	{
		loadAllConfiguration();
		Application::initialize(app);
	}

	void defineOptions(OptionSet &options)
	{
		options.addOption(optConfig);
		options.addOption(optServices);
		options.addOption(optLogging);
		options.addOption(optLogLevel);
		options.addOption(optPort);
		options.addOption(optHelp);
		Application::defineOptions(options);
	}

	int printHelp()
	{
		HelpFormatter help(options());
		help.setCommand(config().getString("application.baseName"));
		help.setUnixStyle(true);
		help.setWidth(80);
		help.setUsage("[-h] ...");
		help.format(cout);

		return EXIT_OK;
	}

	int main(const std::vector <std::string> &args)
	{
		if (m_printHelp)
			return printHelp();

		if (logger().debug())
			ManifestSingleton::reportInfo(logger());

		DependencyInjector injector(config().createView("services"));
		UIServerModule *module = injector
					.create<UIServerModule>("main");

		module->createServer(m_serverPort);
		module->server().start();

		waitForTerminationRequest();
		module->server().stop();
		return EXIT_OK;
	}

private:
	bool m_printHelp;
	unsigned int m_serverPort;
	string m_userLogging;
	string m_userConfig;
	string m_userServices;
};

int main(int argc, char **argv)
{
	Startup server;
	server.setUnixOptions(true);

	try {
		return server.run(argc, argv);
	} catch(Exception &e) {
		cerr << e.displayText() << endl;
	} catch(exception &e) {
		cerr << e.what() << endl;
	} catch(const char *s) {
		cerr << s << endl;
	}
}
<commit_msg>ui: no further processing when -h is given<commit_after>#include <iostream>
#include <Poco/Logger.h>
#include <Poco/Message.h>
#include <Poco/File.h>
#include <Poco/Util/Option.h>
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/HelpFormatter.h>
#include <Poco/Util/ServerApplication.h>

#include "server/MongooseServer.h"
#include "di/DependencyInjector.h"
#include "UIServerModule.h"

using namespace std;
using namespace Poco;
using namespace Poco::Util;
using namespace BeeeOn;

#define DEFAULT_PORT 8000

#define SYSTEM_LOGGING_FILE "/etc/beeeon/ui-server/logging.ini"
#define SYSTEM_CONFIG_FILE "/etc/beeeon/ui-server/server.ini"
#define SYSTEM_SERVICES_FILE "/etc/beeeon/ui-server/services.xml"

static Option optConfig("config", "c",
		"general configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optServices("services", "s",
		"services configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optLogging("logging", "l",
		"logging configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optLogLevel("log-level", "L",
		"change startup log-level (trace, debug, [info],"
		" notice, warn, error, fatal, trace)",
		false,
		"<level>",
		true);
static Option optPort("port", "p",
		"server port to listen on",
		false,
		"<port>",
		true);
static Option optHelp("help", "h", "print help");

class Startup : public ServerApplication {
public:
	Startup():
		m_printHelp(false),
		m_serverPort(DEFAULT_PORT)
	{
	}

protected:
	/**
	 * Extend log-level parsing by shortcuts: info, warn, err, cirt.
	 */
	int parseLogLevel(const string &level)
	{
		if (icompare(level, "info") == 0)
			return Message::PRIO_INFORMATION;
		if (icompare(level, "warn") == 0)
			return Message::PRIO_WARNING;
		if (icompare(level, "err") == 0)
			return Message::PRIO_ERROR;
		if (icompare(level, "crit") == 0)
			return Message::PRIO_CRITICAL;

		return Logger::parseLevel(level);
	}

	void handleOption(const string &name, const string &value)
	{
		if (name == "services")
			m_userServices = value;
		if (name == "logging")
			m_userLogging = value;
		if (name == "config")
			m_userConfig = value;
		if (name == "help")
			m_printHelp = true;
		if (name == "log-level")
			logger().setLevel(parseLogLevel(value));
		if (name == "port")
			m_serverPort = stoi(value);

		if (m_printHelp)
			stopOptionsProcessing();

		Application::handleOption(name, value);
	}

	void loadAllConfiguration()
	{
		findAndLoadConfig();
		findAndLoadLogging();
		findAndLoadServices();
	}

	string parentPath(const File &file)
	{
		Path path(file.path());
		return path.parent().toString();
	}

	bool readConfiguration(const File &file)
	{
		if (!file.exists()) {
			logger().debug("configuration file "
					+ file.path() + " not found");
			return false;
		}

		loadConfiguration(file.path());
		logger().notice("configuration file "
				+ file.path() + " loaded");
		return true;
	}

	void findAndLoadConfig()
	{
		File user(m_userConfig);
		File system(SYSTEM_CONFIG_FILE);

		config().setString("config.dir",
			config().getString("application.dir"));

		if (!m_userConfig.empty() && readConfiguration(user))
			config().setString("config.dir", parentPath(user));
		else if (readConfiguration(system))
			config().setString("config.dir", parentPath(system));
		else
			logger().warning("no main configration found");
	}

	void findAndLoadLogging()
	{
		File user(m_userLogging);
		File system(config().getString(
				"ui.config.logging", SYSTEM_LOGGING_FILE));

		if (!m_userLogging.empty() && readConfiguration(user))
			return;
		else if (!readConfiguration(system.path()))
			logger().warning("no logging configuration found");
	}

	void findAndLoadServices()
	{
		File user(m_userServices);
		File system(config().getString(
				"ui.config.services", SYSTEM_SERVICES_FILE));

		if (!m_userServices.empty() && readConfiguration(user))
			return;
		else if (!readConfiguration(system))
			logger().warning("no services configuration found");
	}

	void initialize(Application &app)
	{
		if (m_printHelp)
			return;

		loadAllConfiguration();
		Application::initialize(app);
	}

	void defineOptions(OptionSet &options)
	{
		options.addOption(optConfig);
		options.addOption(optServices);
		options.addOption(optLogging);
		options.addOption(optLogLevel);
		options.addOption(optPort);
		options.addOption(optHelp);
		Application::defineOptions(options);
	}

	int printHelp()
	{
		HelpFormatter help(options());
		help.setCommand(config().getString("application.baseName"));
		help.setUnixStyle(true);
		help.setWidth(80);
		help.setUsage("[-h] ...");
		help.format(cout);

		return EXIT_OK;
	}

	int main(const std::vector <std::string> &args)
	{
		if (m_printHelp)
			return printHelp();

		if (logger().debug())
			ManifestSingleton::reportInfo(logger());

		DependencyInjector injector(config().createView("services"));
		UIServerModule *module = injector
					.create<UIServerModule>("main");

		module->createServer(m_serverPort);
		module->server().start();

		waitForTerminationRequest();
		module->server().stop();
		return EXIT_OK;
	}

private:
	bool m_printHelp;
	unsigned int m_serverPort;
	string m_userLogging;
	string m_userConfig;
	string m_userServices;
};

int main(int argc, char **argv)
{
	Startup server;
	server.setUnixOptions(true);

	try {
		return server.run(argc, argv);
	} catch(Exception &e) {
		cerr << e.displayText() << endl;
	} catch(exception &e) {
		cerr << e.what() << endl;
	} catch(const char *s) {
		cerr << s << endl;
	}
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>
#include <type_traits>

#include "boost_cfg.hpp"
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"
#include "timing.hpp"
#include "GlobalContext.hpp"

#include "ltac/Statement.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"
#include "mtac/ControlFlowGraph.hpp"
#include "mtac/Statement.hpp"

//The custom optimizations
#include "mtac/conditional_propagation.hpp"
#include "mtac/remove_aliases.hpp"
#include "mtac/clean_variables.hpp"
#include "mtac/remove_unused_functions.hpp"
#include "mtac/remove_empty_functions.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/merge_basic_blocks.hpp"
#include "mtac/remove_dead_basic_blocks.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_analysis.hpp"
#include "mtac/induction_variable_optimizations.hpp"
#include "mtac/loop_unrolling.hpp"
#include "mtac/complete_loop_peeling.hpp"
#include "mtac/remove_empty_loops.hpp"
#include "mtac/loop_invariant_code_motion.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

#include "ltac/Register.hpp"
#include "ltac/FloatRegister.hpp"
#include "ltac/PseudoRegister.hpp"
#include "ltac/PseudoFloatRegister.hpp"
#include "ltac/Address.hpp"

using namespace eddic;

namespace eddic {
namespace mtac {

typedef boost::mpl::vector<
        mtac::ConstantFolding*
    > basic_passes;

struct all_basic_optimizations {};

template<>
struct pass_traits<all_basic_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_basic_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef basic_passes sub_passes;
};

typedef boost::mpl::vector<
        mtac::ArithmeticIdentities*,
        mtac::ReduceInStrength*,
        mtac::ConstantFolding*,
        mtac::conditional_propagation*,
        mtac::ConstantPropagationProblem*,
        mtac::OffsetConstantPropagationProblem*,
        mtac::CommonSubexpressionElimination*,
        mtac::PointerPropagation*,
        mtac::MathPropagation*,
        mtac::optimize_branches*,
        mtac::remove_dead_basic_blocks*,
        mtac::merge_basic_blocks*,
        mtac::dead_code_elimination*,
        mtac::remove_aliases*,
        mtac::loop_analysis*,
        mtac::loop_invariant_code_motion*,
        mtac::loop_induction_variables_optimization*,
        mtac::remove_empty_loops*,
        mtac::complete_loop_peeling*,
        mtac::loop_unrolling*,
        mtac::clean_variables*
    > passes;

struct all_optimizations {};

template<>
struct pass_traits<all_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef passes sub_passes;
};

}
}

namespace {

//TODO Find a more elegant way than using pointers

typedef boost::mpl::vector<
        mtac::all_basic_optimizations*
    > ipa_basic_passes;

typedef boost::mpl::vector<
        mtac::remove_unused_functions*,
        mtac::all_optimizations*,
        mtac::remove_empty_functions*,
        mtac::inline_functions*
    > ipa_passes;

template<typename Pass>
struct need_pool {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_POOL;
};

template<typename Pass>
struct need_platform {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_PLATFORM;
};

template<typename Pass>
struct need_configuration {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_CONFIGURATION;
};

template <bool B, typename T = void>
struct disable_if {
    typedef T type;
};

template <typename T>
struct disable_if<true,T> {
    //SFINAE
};

struct pass_runner {
    bool optimized = false;

    mtac::Program& program;
    mtac::function_p function;

    std::shared_ptr<StringPool> pool;
    std::shared_ptr<Configuration> configuration;
    Platform platform;
    timing_system& system;

    pass_runner(mtac::Program& program, std::shared_ptr<StringPool> pool, std::shared_ptr<Configuration> configuration, Platform platform, timing_system& system) :
            program(program), pool(pool), configuration(configuration), platform(platform), system(system) {};

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP, void>::type remove_nop(){
        for(auto& block : function){
            auto it = iterate(block->statements);

            while(it.has_next()){
                if(unlikely(boost::get<std::shared_ptr<mtac::NoOp>>(&*it))){
                    it.erase();
                    continue;
                } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&*it)){
                    if((*ptr)->op == mtac::Operator::NOP){
                        it.erase();
                        continue;
                    }
                }

                ++it;
            }
        }
    }

    template<typename Pass>
    inline typename std::enable_if<!(mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP), void>::type remove_nop(){
        //NOP
    }

    template<typename Pass>
    inline void apply_todo(){
        remove_nop<Pass>();
    }

    template<typename Pass>
    inline typename std::enable_if<need_pool<Pass>::value, void>::type set_pool(Pass& pass){
        pass.set_pool(pool);
    }

    template<typename Pass>
    inline typename disable_if<need_pool<Pass>::value, void>::type set_pool(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_platform<Pass>::value, void>::type set_platform(Pass& pass){
        pass.set_platform(platform);
    }

    template<typename Pass>
    inline typename disable_if<need_platform<Pass>::value, void>::type set_platform(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass& pass){
        pass.set_configuration(configuration);
    }

    template<typename Pass>
    inline typename disable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass&){
        //NOP
    }

    template<typename Pass>
    Pass make_pass(){
        Pass pass;

        set_pool(pass);
        set_platform(pass);
        set_configuration(pass);

        return pass;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, bool>::type apply(){
        auto pass = make_pass<Pass>();

        return pass(program);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB, bool>::type apply(){
        auto& functions = program.functions;
        for(auto& function : functions){
            this->function = function;

            if(log::enabled<Debug>()){
                LOG<Debug>("Optimizer") << "Start optimizations on " << function->get_name() << log::endl;

                print(function);
            }

            boost::mpl::for_each<typename mtac::pass_traits<Pass>::sub_passes>(boost::ref(*this));
        }

        return false;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::CUSTOM, bool>::type apply(){
        auto pass = make_pass<Pass>();

        return pass(function);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::LOCAL, bool>::type apply(){
        auto visitor = make_pass<Pass>();

        mtac::visit_all_statements(visitor, function);

        return visitor.optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::DATA_FLOW, bool>::type apply(){
        bool optimized = false;

        auto problem = make_pass<Pass>();

        auto results = mtac::data_flow(function, problem);

        //Once the data-flow problem is fixed, statements can be optimized
        for(auto& block : function){
            for(auto& statement : block->statements){
                optimized |= problem.optimize(statement, results);
            }
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB, bool>::type apply(){
        bool optimized = false;

        auto visitor = make_pass<Pass>();

        for(auto& block : function){
            visitor.clear();

            visit_each(visitor, block->statements);

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB_TWO_PASS, bool>::type apply(){
        bool optimized = false;

        auto visitor = make_pass<Pass>();

        for(auto& block : function){
            visitor.clear();

            visitor.pass = mtac::Pass::DATA_MINING;
            visit_each(visitor, block->statements);

            visitor.pass = mtac::Pass::OPTIMIZE;
            visit_each(visitor, block->statements);

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_or<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned " << local << log::endl;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_and<mtac::pass_traits<Pass>::type != mtac::pass_type::IPA, mtac::pass_traits<Pass>::type != mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        if(log::enabled<Debug>()){
            if(local){
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned true" << log::endl;

                //Print the function
                print(function);
            } else {
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned false" << log::endl;
            }
        }
    }

    template<typename Pass>
    inline void operator()(Pass*){
        bool local = false;
        {
            PerfsTimer perfs_timer(mtac::pass_traits<Pass>::name());
            timing_timer timer(system, mtac::pass_traits<Pass>::name());

            local = apply<Pass>();
        }

        if(local){
            program.context->stats().inc_counter(std::string(mtac::pass_traits<Pass>::name()) + "_true");
            apply_todo<Pass>();
        }

        debug_local<Pass>(local);

        optimized |= local;
    }
};

} //end of anonymous namespace

void mtac::Optimizer::optimize(mtac::Program& program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    timing_system timing_system(configuration);
    PerfsTimer timer("Whole optimizations");

    //Build the CFG of each functions (also needed for register allocation)
    for(auto& function : program.functions){
        mtac::build_control_flow_graph(function);
    }

    if(configuration->option_defined("fglobal-optimization")){
        //Apply Interprocedural Optimizations
        pass_runner runner(program, string_pool, configuration, platform, timing_system);
        do{
            runner.optimized = false;
            boost::mpl::for_each<ipa_passes>(boost::ref(runner));
        } while(runner.optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        pass_runner runner(program, string_pool, configuration, platform, timing_system);
        boost::mpl::for_each<ipa_basic_passes>(boost::ref(runner));
    }
}
<commit_msg>Add comment<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>
#include <type_traits>

#include "boost_cfg.hpp"
#include <boost/mpl/vector.hpp>
#include <boost/mpl/for_each.hpp>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"
#include "timing.hpp"
#include "GlobalContext.hpp"

#include "ltac/Statement.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"
#include "mtac/ControlFlowGraph.hpp"
#include "mtac/Statement.hpp"

//The custom optimizations
#include "mtac/conditional_propagation.hpp"
#include "mtac/remove_aliases.hpp"
#include "mtac/clean_variables.hpp"
#include "mtac/remove_unused_functions.hpp"
#include "mtac/remove_empty_functions.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/merge_basic_blocks.hpp"
#include "mtac/remove_dead_basic_blocks.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_analysis.hpp"
#include "mtac/induction_variable_optimizations.hpp"
#include "mtac/loop_unrolling.hpp"
#include "mtac/complete_loop_peeling.hpp"
#include "mtac/remove_empty_loops.hpp"
#include "mtac/loop_invariant_code_motion.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

#include "ltac/Register.hpp"
#include "ltac/FloatRegister.hpp"
#include "ltac/PseudoRegister.hpp"
#include "ltac/PseudoFloatRegister.hpp"
#include "ltac/Address.hpp"

using namespace eddic;

namespace eddic {
namespace mtac {

typedef boost::mpl::vector<
        mtac::ConstantFolding*
    > basic_passes;

struct all_basic_optimizations {};

template<>
struct pass_traits<all_basic_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_basic_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef basic_passes sub_passes;
};

typedef boost::mpl::vector<
        mtac::ArithmeticIdentities*,
        mtac::ReduceInStrength*,
        mtac::ConstantFolding*,
        mtac::conditional_propagation*,
        mtac::ConstantPropagationProblem*,
        mtac::OffsetConstantPropagationProblem*,
        mtac::CommonSubexpressionElimination*,
        mtac::PointerPropagation*,
        mtac::MathPropagation*,
        mtac::optimize_branches*,
        mtac::remove_dead_basic_blocks*,
        mtac::merge_basic_blocks*,
        mtac::dead_code_elimination*,
        mtac::remove_aliases*,
        mtac::loop_analysis*,
        mtac::loop_invariant_code_motion*,
        mtac::loop_induction_variables_optimization*,
        mtac::remove_empty_loops*,
        mtac::complete_loop_peeling*,
        mtac::loop_unrolling*,
        mtac::clean_variables*
    > passes;

struct all_optimizations {};

template<>
struct pass_traits<all_optimizations> {
    STATIC_CONSTANT(pass_type, type, pass_type::IPA_SUB);
    STATIC_STRING(name, "all_optimizations");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);

    typedef passes sub_passes;
};

}
}

namespace {

//TODO Find a more elegant way than using pointers

typedef boost::mpl::vector<
        mtac::all_basic_optimizations*
    > ipa_basic_passes;

typedef boost::mpl::vector<
        mtac::remove_unused_functions*,
        mtac::all_optimizations*,
        mtac::remove_empty_functions*,
        mtac::inline_functions*
    > ipa_passes;

template<typename Pass>
struct need_pool {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_POOL;
};

template<typename Pass>
struct need_platform {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_PLATFORM;
};

template<typename Pass>
struct need_configuration {
    static const bool value = mtac::pass_traits<Pass>::property_flags & mtac::PROPERTY_CONFIGURATION;
};

template <bool B, typename T = void>
struct disable_if {
    typedef T type;
};

template <typename T>
struct disable_if<true,T> {
    //SFINAE
};

struct pass_runner {
    bool optimized = false;

    mtac::Program& program;
    mtac::function_p function; //TODO will be necessary to use a raw pointer here

    std::shared_ptr<StringPool> pool;
    std::shared_ptr<Configuration> configuration;
    Platform platform;
    timing_system& system;

    pass_runner(mtac::Program& program, std::shared_ptr<StringPool> pool, std::shared_ptr<Configuration> configuration, Platform platform, timing_system& system) :
            program(program), pool(pool), configuration(configuration), platform(platform), system(system) {};

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP, void>::type remove_nop(){
        for(auto& block : function){
            auto it = iterate(block->statements);

            while(it.has_next()){
                if(unlikely(boost::get<std::shared_ptr<mtac::NoOp>>(&*it))){
                    it.erase();
                    continue;
                } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&*it)){
                    if((*ptr)->op == mtac::Operator::NOP){
                        it.erase();
                        continue;
                    }
                }

                ++it;
            }
        }
    }

    template<typename Pass>
    inline typename std::enable_if<!(mtac::pass_traits<Pass>::todo_after_flags & mtac::TODO_REMOVE_NOP), void>::type remove_nop(){
        //NOP
    }

    template<typename Pass>
    inline void apply_todo(){
        remove_nop<Pass>();
    }

    template<typename Pass>
    inline typename std::enable_if<need_pool<Pass>::value, void>::type set_pool(Pass& pass){
        pass.set_pool(pool);
    }

    template<typename Pass>
    inline typename disable_if<need_pool<Pass>::value, void>::type set_pool(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_platform<Pass>::value, void>::type set_platform(Pass& pass){
        pass.set_platform(platform);
    }

    template<typename Pass>
    inline typename disable_if<need_platform<Pass>::value, void>::type set_platform(Pass&){
        //NOP
    }

    template<typename Pass>
    inline typename std::enable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass& pass){
        pass.set_configuration(configuration);
    }

    template<typename Pass>
    inline typename disable_if<need_configuration<Pass>::value, void>::type set_configuration(Pass&){
        //NOP
    }

    template<typename Pass>
    Pass make_pass(){
        Pass pass;

        set_pool(pass);
        set_platform(pass);
        set_configuration(pass);

        return pass;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, bool>::type apply(){
        auto pass = make_pass<Pass>();

        return pass(program);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB, bool>::type apply(){
        auto& functions = program.functions;
        for(auto& function : functions){
            this->function = function;

            if(log::enabled<Debug>()){
                LOG<Debug>("Optimizer") << "Start optimizations on " << function->get_name() << log::endl;

                print(function);
            }

            boost::mpl::for_each<typename mtac::pass_traits<Pass>::sub_passes>(boost::ref(*this));
        }

        return false;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::CUSTOM, bool>::type apply(){
        auto pass = make_pass<Pass>();

        return pass(function);
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::LOCAL, bool>::type apply(){
        auto visitor = make_pass<Pass>();

        mtac::visit_all_statements(visitor, function);

        return visitor.optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::DATA_FLOW, bool>::type apply(){
        bool optimized = false;

        auto problem = make_pass<Pass>();

        auto results = mtac::data_flow(function, problem);

        //Once the data-flow problem is fixed, statements can be optimized
        for(auto& block : function){
            for(auto& statement : block->statements){
                optimized |= problem.optimize(statement, results);
            }
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB, bool>::type apply(){
        bool optimized = false;

        auto visitor = make_pass<Pass>();

        for(auto& block : function){
            visitor.clear();

            visit_each(visitor, block->statements);

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<mtac::pass_traits<Pass>::type == mtac::pass_type::BB_TWO_PASS, bool>::type apply(){
        bool optimized = false;

        auto visitor = make_pass<Pass>();

        for(auto& block : function){
            visitor.clear();

            visitor.pass = mtac::Pass::DATA_MINING;
            visit_each(visitor, block->statements);

            visitor.pass = mtac::Pass::OPTIMIZE;
            visit_each(visitor, block->statements);

            optimized |= visitor.optimized;
        }

        return optimized;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_or<mtac::pass_traits<Pass>::type == mtac::pass_type::IPA, mtac::pass_traits<Pass>::type == mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned " << local << log::endl;
    }

    template<typename Pass>
    inline typename std::enable_if<boost::type_traits::ice_and<mtac::pass_traits<Pass>::type != mtac::pass_type::IPA, mtac::pass_traits<Pass>::type != mtac::pass_type::IPA_SUB>::value, void>::type
    debug_local(bool local){
        if(log::enabled<Debug>()){
            if(local){
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned true" << log::endl;

                //Print the function
                print(function);
            } else {
                LOG<Debug>("Optimizer") << mtac::pass_traits<Pass>::name() << " returned false" << log::endl;
            }
        }
    }

    template<typename Pass>
    inline void operator()(Pass*){
        bool local = false;
        {
            PerfsTimer perfs_timer(mtac::pass_traits<Pass>::name());
            timing_timer timer(system, mtac::pass_traits<Pass>::name());

            local = apply<Pass>();
        }

        if(local){
            program.context->stats().inc_counter(std::string(mtac::pass_traits<Pass>::name()) + "_true");
            apply_todo<Pass>();
        }

        debug_local<Pass>(local);

        optimized |= local;
    }
};

} //end of anonymous namespace

void mtac::Optimizer::optimize(mtac::Program& program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    timing_system timing_system(configuration);
    PerfsTimer timer("Whole optimizations");

    //Build the CFG of each functions (also needed for register allocation)
    for(auto& function : program.functions){
        mtac::build_control_flow_graph(function);
    }

    if(configuration->option_defined("fglobal-optimization")){
        //Apply Interprocedural Optimizations
        pass_runner runner(program, string_pool, configuration, platform, timing_system);
        do{
            runner.optimized = false;
            boost::mpl::for_each<ipa_passes>(boost::ref(runner));
        } while(runner.optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        pass_runner runner(program, string_pool, configuration, platform, timing_system);
        boost::mpl::for_each<ipa_basic_passes>(boost::ref(runner));
    }
}
<|endoftext|>