<commit_before>// Basemenu.hh for Fluxbox Window manager
// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxgen at linuxmail.org)
//
// Basemenu.hh for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: Basemenu.hh,v 1.22 2002/12/13 20:39:41 fluxgen Exp $

#ifndef	 BASEMENU_HH
#define	 BASEMENU_HH

#include <X11/Xlib.h>
#include <vector>
#include <string>

#include "FbWindow.hh"
#include "EventHandler.hh"

class BasemenuItem;
class BImageControl;
class BScreen;

/**
   Base class for menus
*/
class Basemenu: public FbTk::EventHandler {
public:
    enum Alignment{ ALIGNDONTCARE = 1, ALIGNTOP, ALIGNBOTTOM };
    enum { RIGHT = 1, LEFT };

    /**
       Bullet type
    */
    enum { EMPTY = 0, SQUARE, TRIANGLE, DIAMOND };

    explicit Basemenu(BScreen *screen);
    virtual ~Basemenu();

    /**
       @name manipulators
    */
    //@{
    int insert(const char *label, int function= 0, const char *exec = 0, int pos = -1);
    int insert(const char *label, Basemenu *submenu, int pos= -1);
    int remove(unsigned int item);
    inline void setInternalMenu() { internal_menu = true; }
    inline void setAlignment(Alignment a) { m_alignment = a; }
    inline void setTorn() { torn = true; }
    inline void removeParent() { if (internal_menu) m_parent = 0; }
    void raise();
    void lower();
    /**
       @name event handlers
    */
    //@{
    void buttonPressEvent(XButtonEvent &bp);
    void buttonReleaseEvent(XButtonEvent &br);
    void motionNotifyEvent(XMotionEvent &mn);
    void enterNotifyEvent(XCrossingEvent &en);
    void leaveNotifyEvent(XCrossingEvent &ce);
    void exposeEvent(XExposeEvent &ee);
    //@}

    void reconfigure();
    /// set label string
    void setLabel(const char *labelstr);
    /// move menu to x,y
    void move(int x, int y);
    void update();
    void setItemSelected(unsigned int index, bool val);
    void setItemEnabled(unsigned int index, bool val);
    virtual void drawSubmenu(unsigned int index);
    virtual void show();
    virtual void hide();
    /*@}*/

    /**
       @name accessors
    */
    //@{
    bool isTorn() const { return torn; }
    bool isVisible() const { return visible; }
    const BScreen *screen() const { return m_screen; }
    BScreen *screen() { return m_screen; }
    Window windowID() const { return menu.window.window(); }
    const std::string &label() const { return menu.label; }
    int x() const { return menu.x; }
    int y() const { return menu.y; }
    unsigned int width() const { return menu.width; }
    unsigned int height() const { return menu.height; }
    unsigned int numberOfItems() const { return menuitems.size(); }
    int currentSubmenu() const { return which_sub; }
    unsigned int titleHeight() const { return menu.title_h; }
    bool hasSubmenu(unsigned int index) const;
    bool isItemSelected(unsigned int index) const;
    bool isItemEnabled(unsigned int index) const;
    //@}

protected:

    inline BasemenuItem *find(unsigned int index) const { return menuitems[index]; }
    inline void setTitleVisibility(bool b) { title_vis = b; }
    inline void setMovable(bool b) { movable = b; }
    inline void setHideTree(bool h) { hide_tree = h; }
    inline void setMinimumSublevels(int m) { menu.minsub = m; }

    virtual void itemSelected(int button, unsigned int index) = 0;
    virtual void drawItem(unsigned int index, bool highlight= false, bool clear= false,
                          int x= -1, int y= -1, unsigned int width= 0, unsigned int height= 0);
    virtual void redrawTitle();
    virtual void internal_hide();
    inline Basemenu *parent() { return m_parent; }
    inline const Basemenu *parent() const { return m_parent; }

private:

    typedef std::vector<BasemenuItem *> Menuitems;
    BScreen *m_screen;
    Display *m_display;
    Basemenu *m_parent;
    BImageControl *m_image_ctrl;
    Menuitems menuitems;

    bool moving, visible, movable, torn, internal_menu, title_vis, shifted,
        hide_tree;

    int which_sub, which_press, which_sbl;
    Alignment m_alignment;

    struct _menu {
        Pixmap frame_pixmap, title_pixmap, hilite_pixmap, sel_pixmap;
        FbTk::FbWindow window, frame, title;

        std::string label;
        int x, y, x_move, y_move, x_shift, y_shift, sublevels, persub, minsub,
            grab_x, grab_y;
        unsigned int width, height, title_h, frame_h, item_w, item_h, bevel_w,
            bevel_h;
    } menu;

};

/**
	A menu item in Basemenu
*/
class BasemenuItem {
public:
    BasemenuItem(
        const char *label,
        int function,
        const char *exec = (const char *) 0)
        : m_label(label ? label : "")
        , m_exec(exec ? exec : "")
        , m_submenu(0)
        , m_function(function)
        , m_enabled(true)
        , m_selected(false)
	{ }

    BasemenuItem(const char *label, Basemenu *submenu)
        : m_label(label ? label : "")
        , m_exec("")
        , m_submenu(submenu)
        , m_function(0)
        , m_enabled(true)
        , m_selected(false)
	{ }

    void setSelected(bool selected) { m_selected = selected; }
    void setEnabled(bool enabled) { m_enabled = enabled; }
    Basemenu *submenu() { return m_submenu; }
    /**
        @name accessors
    */
    //@{
    const std::string &exec() const { return m_exec; }
    const std::string &label() const { return m_label; }
    int function() const { return m_function; }
    const Basemenu *submenu() const { return m_submenu; }
    bool isEnabled() const { return m_enabled; }
    bool isSelected() const { return m_selected; }
    //@}

private:
    std::string m_label; ///< label of this item
    std::string m_exec;  ///< command string to execute
    Basemenu *m_submenu; ///< a submenu, 0 if we don't have one
    int m_function;
    bool m_enabled, m_selected;

    friend class Basemenu;
};

#endif // BASEMENU_HH
<commit_msg>adjusted for FbTk imagecontrol<commit_after>// Basemenu.hh for Fluxbox Window manager
// Copyright (c) 2001 - 2002 Henrik Kinnunen (fluxgen at linuxmail.org)
//
// Basemenu.hh for Blackbox - an X11 Window manager
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: Basemenu.hh,v 1.23 2003/01/09 21:57:46 fluxgen Exp $

#ifndef	 BASEMENU_HH
#define	 BASEMENU_HH

#include <X11/Xlib.h>
#include <vector>
#include <string>

#include "FbWindow.hh"
#include "EventHandler.hh"

class BasemenuItem;
class BScreen;

namespace FbTk {
class ImageControl;
};

/**
   Base class for menus
*/
class Basemenu: public FbTk::EventHandler {
public:
    enum Alignment{ ALIGNDONTCARE = 1, ALIGNTOP, ALIGNBOTTOM };
    enum { RIGHT = 1, LEFT };

    /**
       Bullet type
    */
    enum { EMPTY = 0, SQUARE, TRIANGLE, DIAMOND };

    explicit Basemenu(BScreen *screen);
    virtual ~Basemenu();

    /**
       @name manipulators
    */
    //@{
    int insert(const char *label, int function= 0, const char *exec = 0, int pos = -1);
    int insert(const char *label, Basemenu *submenu, int pos= -1);
    int remove(unsigned int item);
    inline void setInternalMenu() { internal_menu = true; }
    inline void setAlignment(Alignment a) { m_alignment = a; }
    inline void setTorn() { torn = true; }
    inline void removeParent() { if (internal_menu) m_parent = 0; }
    void raise();
    void lower();
    /**
       @name event handlers
    */
    //@{
    void buttonPressEvent(XButtonEvent &bp);
    void buttonReleaseEvent(XButtonEvent &br);
    void motionNotifyEvent(XMotionEvent &mn);
    void enterNotifyEvent(XCrossingEvent &en);
    void leaveNotifyEvent(XCrossingEvent &ce);
    void exposeEvent(XExposeEvent &ee);
    //@}

    void reconfigure();
    /// set label string
    void setLabel(const char *labelstr);
    /// move menu to x,y
    void move(int x, int y);
    void update();
    void setItemSelected(unsigned int index, bool val);
    void setItemEnabled(unsigned int index, bool val);
    virtual void drawSubmenu(unsigned int index);
    virtual void show();
    virtual void hide();
    /*@}*/

    /**
       @name accessors
    */
    //@{
    bool isTorn() const { return torn; }
    bool isVisible() const { return visible; }
    const BScreen *screen() const { return m_screen; }
    BScreen *screen() { return m_screen; }
    Window windowID() const { return menu.window.window(); }
    const std::string &label() const { return menu.label; }
    int x() const { return menu.x; }
    int y() const { return menu.y; }
    unsigned int width() const { return menu.width; }
    unsigned int height() const { return menu.height; }
    unsigned int numberOfItems() const { return menuitems.size(); }
    int currentSubmenu() const { return which_sub; }
    unsigned int titleHeight() const { return menu.title_h; }
    bool hasSubmenu(unsigned int index) const;
    bool isItemSelected(unsigned int index) const;
    bool isItemEnabled(unsigned int index) const;
    //@}

protected:

    inline BasemenuItem *find(unsigned int index) const { return menuitems[index]; }
    inline void setTitleVisibility(bool b) { title_vis = b; }
    inline void setMovable(bool b) { movable = b; }
    inline void setHideTree(bool h) { hide_tree = h; }
    inline void setMinimumSublevels(int m) { menu.minsub = m; }

    virtual void itemSelected(int button, unsigned int index) = 0;
    virtual void drawItem(unsigned int index, bool highlight= false, bool clear= false,
                          int x= -1, int y= -1, unsigned int width= 0, unsigned int height= 0);
    virtual void redrawTitle();
    virtual void internal_hide();
    inline Basemenu *parent() { return m_parent; }
    inline const Basemenu *parent() const { return m_parent; }

private:

    typedef std::vector<BasemenuItem *> Menuitems;
    BScreen *m_screen;
    Display *m_display;
    Basemenu *m_parent;
    FbTk::ImageControl *m_image_ctrl;
    Menuitems menuitems;

    bool moving, visible, movable, torn, internal_menu, title_vis, shifted,
        hide_tree;

    int which_sub, which_press, which_sbl;
    Alignment m_alignment;

    struct _menu {
        Pixmap frame_pixmap, title_pixmap, hilite_pixmap, sel_pixmap;
        FbTk::FbWindow window, frame, title;

        std::string label;
        int x, y, x_move, y_move, x_shift, y_shift, sublevels, persub, minsub,
            grab_x, grab_y;
        unsigned int width, height, title_h, frame_h, item_w, item_h, bevel_w,
            bevel_h;
    } menu;

};

/**
	A menu item in Basemenu
*/
class BasemenuItem {
public:
    BasemenuItem(
        const char *label,
        int function,
        const char *exec = (const char *) 0)
        : m_label(label ? label : "")
        , m_exec(exec ? exec : "")
        , m_submenu(0)
        , m_function(function)
        , m_enabled(true)
        , m_selected(false)
	{ }

    BasemenuItem(const char *label, Basemenu *submenu)
        : m_label(label ? label : "")
        , m_exec("")
        , m_submenu(submenu)
        , m_function(0)
        , m_enabled(true)
        , m_selected(false)
	{ }

    void setSelected(bool selected) { m_selected = selected; }
    void setEnabled(bool enabled) { m_enabled = enabled; }
    Basemenu *submenu() { return m_submenu; }
    /**
        @name accessors
    */
    //@{
    const std::string &exec() const { return m_exec; }
    const std::string &label() const { return m_label; }
    int function() const { return m_function; }
    const Basemenu *submenu() const { return m_submenu; }
    bool isEnabled() const { return m_enabled; }
    bool isSelected() const { return m_selected; }
    //@}

private:
    std::string m_label; ///< label of this item
    std::string m_exec;  ///< command string to execute
    Basemenu *m_submenu; ///< a submenu, 0 if we don't have one
    int m_function;
    bool m_enabled, m_selected;

    friend class Basemenu;
};

#endif // BASEMENU_HH
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・SCI I/O 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2013, 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"

/// F_PCLKB はボーレートパラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCLKB
#  error "sci_io.hpp requires F_PCLKB to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCI I/O 制御クラス
		@param[in]	SCI	SCI 定義クラス
		@param[in]	RECV_BUFF	受信バッファクラス
		@param[in]	SEND_BUFF	送信バッファクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCI, class RECV_BUFF, class SEND_BUFF>
	class sci_io {

		static RECV_BUFF recv_;
		static SEND_BUFF send_;
		static volatile bool send_stall_;

		uint8_t	level_;
		bool	crlf_;

		// ※必要なら、実装する
		void sleep_() { asm("nop"); }

		static INTERRUPT_FUNC void recv_task_()
		{
			bool err = false;
			if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
				SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				err = true;
			}
			///< フレーミングエラー/パリティエラー状態確認
			if(SCI::SSR() & (SCI::SSR.FER.b() | SCI::SSR.PER.b())) {
				// エラーフラグの消去
				SCI::SSR.FER = 0;
				SCI::SSR.PER = 0;
				err = true;
			}
			volatile uint8_t data = SCI::RDR();
			if(!err) {
				recv_.put(data);
			}
		}

		static INTERRUPT_FUNC void send_task_()
		{
#if SIG_RX64M
			if(send_.length() > 0) {
				SCI::TDR = send_.get();
			}
			if(send_.length() == 0) {
				SCI::SCR.TIE = 0;
				send_stall_ = true;
			}
#else
			SCI::TDR = send_.get();
			if(send_.length() == 0) {
				SCI::SCR.TEIE = 0;
			}
#endif
		}

		void set_vector_(ICU::VECTOR rx_vec, ICU::VECTOR tx_vec) {
			if(level_) {
				set_interrupt_task(recv_task_, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(send_task_, static_cast<uint32_t>(tx_vec));
			} else {
				set_interrupt_task(nullptr, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(nullptr, static_cast<uint32_t>(tx_vec));
			}
		}

		void set_intr_() {
#if SIG_RX64M
			set_vector_(SCI::get_rx_vec(), SCI::get_tx_vec());
#else
			set_vector_(SCI::get_rx_vec(), SCI::get_te_vec());
#endif
			icu_mgr::set_level(SCI::get_peripheral(), level_);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		sci_io() : level_(0), crlf_(true) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  ボーレートを設定して、SCI を有効にする @n
					※RX63T では、ポーリングはサポート外
			@param[in]	baud	ボーレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t baud, uint8_t level = 0) {
			send_stall_ = true;
#if SIG_RX63T
			if(level == 0) return false;
#endif
			crlf_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			port_map::turn(SCI::get_peripheral());

			uint32_t brr = F_PCLKB / baud / 16;
			uint8_t cks = 0;
			while(brr > 512) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3) return false;
			bool abcs = true;
			if(brr > 256) { brr /= 2; abcs = false; }

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// 8 bits, 1 stop bit, no-parrity
			SCI::SMR = cks;
			SCI::SEMR.ABCS = abcs;
			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			if(level) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b();
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b();
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  通信速度を設定して、SPI を有効にする
			@param[in]	master	マスターモードの場合「true」
			@param[in]	bps	ビットレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start_spi(bool master, uint32_t bps, uint8_t level = 0)
		{
			send_stall_ = true;
			crlf_ = false;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			uint32_t brr = F_PCLKB / bps / 2;
			if(brr & 1) { brr >>= 1; ++brr; }
			else { brr >>= 1; }
			uint8_t cks = 0;
			while(brr > 256) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3 || brr > 256) return false;

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// LSB(0), MSB(1) first
			SCI::SCMR.SDIR = 1;

			SCI::SIMR1.IICM = 0;
			SCI::SMR = cks | SCI::SMR.CM.b();
			SCI::SPMR.SSE = 0;		///< SS 端子制御しない「０」

			if(master) {
				SCI::SPMR.MSS = 0;
			} else {
				SCI::SPMR.MSS = 1;
			}

			// クロックタイミング種別選択
			SCI::SPMR.CKPOL = 0;
			SCI::SPMR.CKPH  = 0;

			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			uint8_t scr = 0;
			if(master) {
				scr = SCI::SCR.CKE.b(0b01);
			} else {
				scr = SCI::SCR.CKE.b(0b10);
			}

			if(level_) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	CRLF 自動送出
			@param[in]	f	「false」なら無効
		 */
		//-----------------------------------------------------------------//
		void auto_crlf(bool f = true) { crlf_ = f; }

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 出力バッファのサイズを返す
			@return　バッファのサイズ
		 */
		//-----------------------------------------------------------------//
		uint32_t send_length() const {
			if(level_) {
				return send_.length();
			} else {
				return 0;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字出力
			@param[in]	ch	文字コード
		 */
		//-----------------------------------------------------------------//
		void putch(char ch) {
			if(crlf_ && ch == '\n') {
				putch('\r');
			}

			if(level_) {
				volatile bool b = SCI::SSR.ORER();
				if(b) {
					SCI::SSR.ORER = 0;
				}
				/// 送信バッファの容量が７／８の場合は、空になるまで待つ。
				if(send_.length() >= (send_.size() * 7 / 8)) {
					while(send_.length() != 0) sleep_();
				}
				send_.put(ch);
#if SIG_RX64M
				SCI::SCR.TIE = 0;
				if(send_stall_) {
					while(SCI::SSR.TEND() == 0) sleep_();
					SCI::TDR = send_.get();
					if(send_.length() > 0) {
						send_stall_ = false;
					}
				}
				SCI::SCR.TIE = !send_stall_;
#else
				if(SCI::SCR.TEIE() == 0) {
					SCI::SCR.TEIE = 1;
				}
#endif
			} else {
				while(SCI::SSR.TEND() == 0) sleep_();
				SCI::TDR = ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 入力文字数を取得
			@return	入力文字数
		 */
		//-----------------------------------------------------------------//
		uint32_t recv_length() {
			if(level_) {
				return recv_.length();
			} else {
				if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
					SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				}
#if defined(SIG_RX64M) || defined(SIG_RX24T)
				auto n = SCI::SSR.RDRF();
#else
				uint32_t n = 0;
#endif
				return n;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字入力
			@return 文字コード
		 */
		//-----------------------------------------------------------------//
		char getch() {
			if(level_) {
				while(recv_.length() == 0) sleep_();
				return recv_.get();
			} else {
				char ch;
				while(recv_length() == 0) sleep_();
				ch = SCI::RDR();	///< 受信データ読み出し
				return ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	uart文字列出力
			@param[in]	s	出力ストリング
		 */
		//-----------------------------------------------------------------//
		void puts(const char* s) {
			char ch;
			while((ch = *s++) != 0) {
				putch(ch);
			}
		}
	};

	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		RECV_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::recv_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		SEND_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		volatile bool sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_stall_;
}
<commit_msg>update SPI api for SCI interface<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・SCI I/O 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2013, 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"

/// F_PCLKB はボーレートパラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCLKB
#  error "sci_io.hpp requires F_PCLKB to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  SCI I/O 制御クラス
		@param[in]	SCI	SCI 定義クラス
		@param[in]	RECV_BUFF	受信バッファクラス
		@param[in]	SEND_BUFF	送信バッファクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCI, class RECV_BUFF, class SEND_BUFF>
	class sci_io {

		static RECV_BUFF recv_;
		static SEND_BUFF send_;
		static volatile bool send_stall_;

		uint8_t	level_;
		bool	crlf_;

		// ※必要なら、実装する
		void sleep_() { asm("nop"); }

		static INTERRUPT_FUNC void recv_task_()
		{
			bool err = false;
			if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
				SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				err = true;
			}
			///< フレーミングエラー/パリティエラー状態確認
			if(SCI::SSR() & (SCI::SSR.FER.b() | SCI::SSR.PER.b())) {
				// エラーフラグの消去
				SCI::SSR.FER = 0;
				SCI::SSR.PER = 0;
				err = true;
			}
			volatile uint8_t data = SCI::RDR();
			if(!err) {
				recv_.put(data);
			}
		}

		static INTERRUPT_FUNC void send_task_()
		{
#if SIG_RX64M
			if(send_.length() > 0) {
				SCI::TDR = send_.get();
			}
			if(send_.length() == 0) {
				SCI::SCR.TIE = 0;
				send_stall_ = true;
			}
#else
			SCI::TDR = send_.get();
			if(send_.length() == 0) {
				SCI::SCR.TEIE = 0;
			}
#endif
		}

		void set_vector_(ICU::VECTOR rx_vec, ICU::VECTOR tx_vec) {
			if(level_) {
				set_interrupt_task(recv_task_, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(send_task_, static_cast<uint32_t>(tx_vec));
			} else {
				set_interrupt_task(nullptr, static_cast<uint32_t>(rx_vec));
				set_interrupt_task(nullptr, static_cast<uint32_t>(tx_vec));
			}
		}

		void set_intr_() {
#if SIG_RX64M
			set_vector_(SCI::get_rx_vec(), SCI::get_tx_vec());
#else
			set_vector_(SCI::get_rx_vec(), SCI::get_te_vec());
#endif
			icu_mgr::set_level(SCI::get_peripheral(), level_);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		sci_io() : level_(0), crlf_(true) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  ボーレートを設定して、SCI を有効にする @n
					※RX63T では、ポーリングはサポート外
			@param[in]	baud	ボーレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t baud, uint8_t level = 0) {
			send_stall_ = true;
#if SIG_RX63T
			if(level == 0) return false;
#endif
			crlf_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			port_map::turn(SCI::get_peripheral());

			uint32_t brr = F_PCLKB / baud / 16;
			uint8_t cks = 0;
			while(brr > 512) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3) return false;
			bool abcs = true;
			if(brr > 256) { brr /= 2; abcs = false; }

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// 8 bits, 1 stop bit, no-parrity
			SCI::SMR = cks;
			SCI::SEMR.ABCS = abcs;
			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			if(level) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b();
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b();
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  通信速度を設定して、SPI を有効にする
			@param[in]	master	マスターモードの場合「true」
			@param[in]	bps	ビットレート
			@param[in]	level	割り込みレベル（０の場合ポーリング）
			@return エラーなら「false」
		*/
		//-----------------------------------------------------------------//
		bool start_spi(bool master, uint32_t bps, uint8_t level = 0)
		{
			send_stall_ = true;
			level_ = level;

			SCI::SCR = 0x00;			// TE, RE disable.

			uint32_t brr = F_PCLKB / bps / 2;
			if(brr & 1) { brr >>= 1; ++brr; }
			else { brr >>= 1; }
			uint8_t cks = 0;
			while(brr > 256) {
				brr >>= 2;
				++cks;
			}
			if(cks > 3 || brr > 256) return false;

			power_cfg::turn(SCI::get_peripheral());

			set_intr_();

			// LSB(0), MSB(1) first
			SCI::SCMR.SDIR = 1;

			SCI::SIMR1.IICM = 0;
			SCI::SMR = cks | SCI::SMR.CM.b();
			SCI::SPMR.SSE = 0;		///< SS 端子制御しない「０」

			if(master) {
				SCI::SPMR.MSS = 0;
			} else {
				SCI::SPMR.MSS = 1;
			}

			// クロックタイミング種別選択
			SCI::SPMR.CKPOL = 0;
			SCI::SPMR.CKPH  = 0;

			if(brr) --brr;
			SCI::BRR = static_cast<uint8_t>(brr);

			uint8_t scr = 0;
			if(master) {
				scr = SCI::SCR.CKE.b(0b01);
			} else {
				scr = SCI::SCR.CKE.b(0b10);
			}

			if(level_) {
				SCI::SCR = SCI::SCR.RIE.b() | SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			} else {
				SCI::SCR = SCI::SCR.TE.b() | SCI::SCR.RE.b() | scr;
			}

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	CRLF 自動送出
			@param[in]	f	「false」なら無効
		 */
		//-----------------------------------------------------------------//
		void auto_crlf(bool f = true) { crlf_ = f; }

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 出力バッファのサイズを返す
			@return　バッファのサイズ
		 */
		//-----------------------------------------------------------------//
		uint32_t send_length() const {
			if(level_) {
				return send_.length();
			} else {
				return 0;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字出力
			@param[in]	ch	文字コード
		 */
		//-----------------------------------------------------------------//
		void putch(char ch) {
			if(crlf_ && ch == '\n') {
				putch('\r');
			}

			if(level_) {
				volatile bool b = SCI::SSR.ORER();
				if(b) {
					SCI::SSR.ORER = 0;
				}
				/// 送信バッファの容量が７／８の場合は、空になるまで待つ。
				if(send_.length() >= (send_.size() * 7 / 8)) {
					while(send_.length() != 0) sleep_();
				}
				send_.put(ch);
#if SIG_RX64M
				SCI::SCR.TIE = 0;
				if(send_stall_) {
					while(SCI::SSR.TEND() == 0) sleep_();
					SCI::TDR = send_.get();
					if(send_.length() > 0) {
						send_stall_ = false;
					}
				}
				SCI::SCR.TIE = !send_stall_;
#else
				if(SCI::SCR.TEIE() == 0) {
					SCI::SCR.TEIE = 1;
				}
#endif
			} else {
				while(SCI::SSR.TEND() == 0) sleep_();
				SCI::TDR = ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 入力文字数を取得
			@return	入力文字数
		 */
		//-----------------------------------------------------------------//
		uint32_t recv_length() {
			if(level_) {
				return recv_.length();
			} else {
				if(SCI::SSR.ORER()) {	///< 受信オーバランエラー状態確認
					SCI::SSR.ORER = 0;	///< 受信オーバランエラークリア
				}
#if defined(SIG_RX64M) || defined(SIG_RX24T)
				auto n = SCI::SSR.RDRF();
#else
				uint32_t n = 0;
#endif
				return n;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	SCI 文字入力
			@return 文字コード
		 */
		//-----------------------------------------------------------------//
		char getch() {
			if(level_) {
				while(recv_.length() == 0) sleep_();
				return recv_.get();
			} else {
				char ch;
				while(recv_length() == 0) sleep_();
				ch = SCI::RDR();	///< 受信データ読み出し
				return ch;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	uart文字列出力
			@param[in]	s	出力ストリング
		 */
		//-----------------------------------------------------------------//
		void puts(const char* s) {
			char ch;
			while((ch = *s++) != 0) {
				putch(ch);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送受信
			@param[in]	ch	送信データ
			@return	受信データ
		*/
		//-----------------------------------------------------------------//
		inline uint8_t xchg(uint8_t ch = 0xff)
		{
			if(level_) {
				return 0;
			} else {
				SCI::TDR = ch;
				while(recv_length() == 0) sleep_();
				return SCI::RDR();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル送信
			@param[in]	src	送信ソース
			@param[in]	cnt	送信サイズ
		*/
		//-----------------------------------------------------------------//
		void send(const void* src, uint16_t size)
		{
			const uint8_t* p = static_cast<const uint8_t*>(src);
			auto end = p + size;
			while(p < end) {
				xchg(*p);
				++p;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル受信
			@param[out]	dst	受信先
			@param[in]	cnt	受信サイズ
		*/
		//-----------------------------------------------------------------//
		void recv(void* dst, uint16_t size)
		{
			uint8_t* p = static_cast<uint8_t*>(dst);
			auto end = p + size;
			while(p < end) {
				*p = xchg();
				++p;
			}
		}
	};

	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		RECV_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::recv_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		SEND_BUFF sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_;
	template<class SCI, class RECV_BUFF, class SEND_BUFF>
		volatile bool sci_io<SCI, RECV_BUFF, SEND_BUFF>::send_stall_;
}
<|endoftext|>


<commit_before>
#include <cstdlib>
#include <ctime>

#include <chrono>
#include <future>
#include <memory>
#include <sstream>
#include <string>
#include <thread>

#include <gtest/gtest.h>

#include <concurrent_map/concurrent_map.h>

class MapTest : public ::testing::Test {
  protected:

    using map_ptr_t = std::unique_ptr<concurrent::map>;
    map_ptr_t map_;

    virtual void SetUp() {
        map_ = map_ptr_t( new concurrent::map() );
    }

    virtual void TearDown() {
        map_.reset();
    }

};

TEST_F( MapTest, should_contains_value ) {
    auto key = std::string( "key" );
    auto value = std::string( "value" );

    map_->set( key, value );

    auto actual = map_->get( key );

    EXPECT_STREQ( value.c_str(), actual.c_str() );
}

TEST_F( MapTest, should_emplace_new_value_if_not_exist ) {
    auto key = std::string( "key" );
    auto expected_value = std::string( "" );

    auto actual = map_->get( key );

    EXPECT_STREQ( expected_value.c_str(), actual.c_str() );
}

TEST_F( MapTest, should_be_thread_safe ) {
    std::srand( std::time( 0 ) );

    auto f = [this]( concurrent::map::key_t key, concurrent::map::value_t value ) {
        auto ss = std::stringstream();
        auto id = std::this_thread::get_id();

        ss << id;

        auto i = 100;

        while( i-- ) {
            map_->set( std::to_string( i ), ss.str() );

            map_->set( key, value );

            std::this_thread::sleep_for( std::chrono::milliseconds( std::rand() % 10 ) );
        }
    };

    auto key1 = std::string( "key1" );
    auto key2 = std::string( "key2" );

    auto expected_value1 = std::string( "foo" );
    auto expected_value2 = std::string( "bar" );

    auto fut1 = std::async( std::launch::async, f, key1, expected_value1 );
    auto fut2 = std::async( std::launch::async, f, key2, expected_value2 );

    fut1.wait();
    fut2.wait();

    auto actual1 = map_->get( key1 );
    EXPECT_STREQ( expected_value1.c_str(), actual1.c_str() );

    auto actual2 = map_->get( key2 );
    EXPECT_STREQ( expected_value2.c_str(), actual2.c_str() );
}

TEST_F( MapTest, should_provide_exclusive_access_get ) {
    auto key = std::string( "key" );
    auto value = std::string( "value" );

    auto access_token = map_->get_exclusive_access( key );

    auto fut = std::async( std::launch::async, [this, key] {
        map_->get( key );
    } );

    auto status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::timeout );

    map_->set( key, value );

    auto actual = map_->get( key );

    EXPECT_STREQ( value.c_str(), actual.c_str() );

    /// release token to avoid a deadlock into the destructor of the std::future from std::async()
    access_token.release();
}

TEST_F( MapTest, should_provide_exclusive_access_set ) {
    auto key = std::string( "key" );
    auto value = std::string( "value" );

    auto access_token = map_->get_exclusive_access( key );

    auto fut = std::async( std::launch::async, [this, key] {
        map_->set( key, "bar" );
    } );

    auto status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::timeout );

    map_->set( key, value );

    auto actual = map_->get( key );

    EXPECT_STREQ( value.c_str(), actual.c_str() );

    /// release token to avoid a deadlock into the destructor of the std::future from std::async()
    access_token.release();
}<commit_msg>A couple of new tests.<commit_after>
#include <cstdlib>
#include <ctime>

#include <chrono>
#include <future>
#include <memory>
#include <sstream>
#include <string>
#include <thread>

#include <gtest/gtest.h>

#include <concurrent_map/concurrent_map.h>

class MapTest : public ::testing::Test {
  protected:

    using map_ptr_t = std::unique_ptr<concurrent::map>;
    map_ptr_t map_;

    virtual void SetUp() {
        map_ = map_ptr_t( new concurrent::map() );
    }

    virtual void TearDown() {
        map_.reset();
    }

};

TEST_F( MapTest, should_contains_value ) {
    auto key = std::string( "key" );
    auto value = std::string( "value" );

    map_->set( key, value );

    auto actual = map_->get( key );

    EXPECT_STREQ( value.c_str(), actual.c_str() );
}

TEST_F( MapTest, should_emplace_new_value_if_not_exist ) {
    auto key = std::string( "key" );
    auto expected_value = std::string( "" );

    auto actual = map_->get( key );

    EXPECT_STREQ( expected_value.c_str(), actual.c_str() );
}

TEST_F( MapTest, should_be_thread_safe ) {
    std::srand( std::time( 0 ) );

    auto f = [this]( concurrent::map::key_t key, concurrent::map::value_t value ) {
        auto ss = std::stringstream();
        auto id = std::this_thread::get_id();

        ss << id;

        auto i = 100;

        while( i-- ) {
            map_->set( std::to_string( i ), ss.str() );

            map_->set( key, value );

            std::this_thread::sleep_for( std::chrono::milliseconds( std::rand() % 10 ) );
        }
    };

    auto key1 = std::string( "key1" );
    auto key2 = std::string( "key2" );

    auto expected_value1 = std::string( "foo" );
    auto expected_value2 = std::string( "bar" );

    auto fut1 = std::async( std::launch::async, f, key1, expected_value1 );
    auto fut2 = std::async( std::launch::async, f, key2, expected_value2 );

    fut1.wait();
    fut2.wait();

    auto actual1 = map_->get( key1 );
    EXPECT_STREQ( expected_value1.c_str(), actual1.c_str() );

    auto actual2 = map_->get( key2 );
    EXPECT_STREQ( expected_value2.c_str(), actual2.c_str() );
}

TEST_F( MapTest, should_provide_exclusive_access_get ) {
    auto key = std::string( "key" );
    auto value = std::string( "value" );

    auto access_token = map_->get_exclusive_access( key );

    auto fut = std::async( std::launch::async, [this, key] {
        map_->get( key );
    } );

    auto status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::timeout );

    map_->set( key, value );

    auto actual = map_->get( key );

    EXPECT_STREQ( value.c_str(), actual.c_str() );

    /// release token to avoid a deadlock into the destructor of the std::future from std::async()
    access_token.release();
}

TEST_F( MapTest, should_provide_exclusive_access_set ) {
    auto key = std::string( "key" );
    auto value = std::string( "value" );

    auto access_token = map_->get_exclusive_access( key );

    auto fut = std::async( std::launch::async, [this, key] {
        map_->set( key, "bar" );
    } );

    auto status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::timeout );

    map_->set( key, value );

    auto actual = map_->get( key );

    EXPECT_STREQ( value.c_str(), actual.c_str() );

    /// release token to avoid a deadlock into the destructor of the std::future from std::async()
    access_token.release();
}

TEST_F( MapTest, should_provide_exclusive_access_different_keys ) {
    auto key1 = std::string( "key1" );
    auto key2 = std::string( "key2" );
    auto value1 = std::string( "value1" );
    auto value2 = std::string( "value2" );

    auto access_token = map_->get_exclusive_access( key1 );

    auto fut = std::async( std::launch::async, [this, key2, value2] {
        map_->set( key2, value2 );
    } );

    auto status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::ready );

    map_->set( key1, value1 );

    auto actual1 = map_->get( key1 );

    EXPECT_STREQ( value1.c_str(), actual1.c_str() );

    access_token.release();

    auto actual2 = map_->get( key2 );

    EXPECT_STREQ( value2.c_str(), actual2.c_str() );
}

TEST_F( MapTest, should_provide_exclusive_access_many_keys ) {
    auto key1 = std::string( "key1" );
    auto key2 = std::string( "key2" );
    auto value1 = std::string( "value1" );
    auto value2 = std::string( "value2" );

    auto access_token1 = map_->get_exclusive_access( key1 );
    auto access_token2 = map_->get_exclusive_access( key2 );

    auto fut = std::async( std::launch::async, [this, key1, key2, value2] {
        map_->set( key1, value2 );
        map_->set( key2, value2 );
    } );

    auto status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::timeout );

    map_->set( key1, value1 );
    map_->set( key2, value1 );

    auto actual1 = map_->get( key1 );

    EXPECT_STREQ( value1.c_str(), actual1.c_str() );

    auto actual2 = map_->get( key2 );

    EXPECT_STREQ( value1.c_str(), actual2.c_str() );

    access_token1.release();

    status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::timeout );

    auto actual3 = map_->get( key1 );

    EXPECT_STREQ( value2.c_str(), actual3.c_str() );

    access_token2.release();

    status = fut.wait_for( std::chrono::milliseconds( 500 ) );
    EXPECT_TRUE( status == std::future_status::ready );

    auto actual4 = map_->get( key2 );

    EXPECT_STREQ( value2.c_str(), actual4.c_str() );
}
<|endoftext|>


<commit_before>/*
 * main.cpp
 *
 *  Created on: 23.03.2017 г.
 *      Author: trifon
 */

#include <iostream>
#include <cstring>
#include "player.h"
#include "hero.h"
#include "superhero.h"

void anonymousPrint(Player p) {
	std::cout << p;
	p.setName("Анонимен");
	std::cout << p;
}

void testPlayer() {
	Player p1("Гандалф Сивия", 45);
	p1.print();
	Player p2;
	p2 = p1;
	// !!! p2 = p2;
	p2.print();
	p2.setName("Гандалф Белия");
	p1.print();
	p2.print();
	anonymousPrint(p2);
	p1.print();
	p2.print();
	// !!! strcpy(p1.getName(), "PWNED!!11!");
	// !!! p1.print();
	Player p3 = "Кетнис Евърдийн";
	// Player p3("Кетнис Евърдийн");
	p3.print();
	// !!! Player p4 = 5;
	anonymousPrint("Фродо");

	std::cin >> p1;
	std::cout << p1;
}

void testDestructor() {
	for(int i = 0; i < 1E8; i++) {
		Player p("Гандалф Сивия", 45);
		p.setScore(50);
		// !!! delete p.getName();
	}

	for(int i = 0; i < 1E8; i++) {
		Player* p = new Player[10];
		delete[] p;
	}

	Player* pa[10];
	for(int i = 0; i < 10; i++) {
		pa[i] = new Player("Орк");
		pa[i]->print();
	}

	delete pa[2];
	delete pa[8];

	for(int i = 0; i < 10; i++)
		if (i != 2 && i != 8)
			delete pa[i];
}

void testInheritance() {
	Player p("Гандалф Сивия", 45);
	Hero h("Кетнис Евърдийн", 50, 3);
	p.print();std::cout << std::endl;
	h.print();std::cout << std::endl;
	std::cout << p;
	std::cout << h;
	Player* p2 = &h;
	p2->print();std::cout << std::endl;
	h.setScore(55);
	p2->print();std::cout << std::endl;
	// !!!
	Hero* h2 = (Hero*)&p;
	h2->print();std::cout << std::endl;
	Hero& h3 = (Hero&)*p2;
	// Hero& h3 = *(Hero*)p2;
	h3.print();std::cout << std::endl;
}

void nl() {
	std::cout << std::endl;
}

void testBattle() {
	Player catniss("Кетнис Евърдийн", 50);
	Hero gandalf("Гандалф Сивия", 45, 3);
	SuperHero superman("Супермен", 10, 2, "летене");
	catniss.print();nl();
	gandalf.print();nl();
	superman.print();nl();
	superman.becomeSuperHero();
	superman.print();nl();

	Hero gandalfw; //= gandalf;
	gandalfw = gandalf;
	gandalfw.setName("Гандалф Белия");
	gandalf.print();nl();
	gandalfw.print();nl();

	SuperHero superwoman;// = superman;
	superwoman = superman;
	superwoman.setName("Супержена");
	superwoman.print();nl();
	superman.print();nl();
}

/*
class ChessPlayer : public Player {
private:
	int elo;
};
*/

int main() {
	// testPlayer();
	// testDestructor();
	// testInheritance();
	testBattle();

	// ChessPlayer cp;
	return 0;
}

<commit_msg>Битка между герои. Проблем: SuperHero не може да активира силата си!<commit_after>/*
 * main.cpp
 *
 *  Created on: 23.03.2017 г.
 *      Author: trifon
 */

#include <iostream>
#include <cstring>
#include "player.h"
#include "hero.h"
#include "superhero.h"

void anonymousPrint(Player p) {
	std::cout << p;
	p.setName("Анонимен");
	std::cout << p;
}

void testPlayer() {
	Player p1("Гандалф Сивия", 45);
	p1.print();
	Player p2;
	p2 = p1;
	// !!! p2 = p2;
	p2.print();
	p2.setName("Гандалф Белия");
	p1.print();
	p2.print();
	anonymousPrint(p2);
	p1.print();
	p2.print();
	// !!! strcpy(p1.getName(), "PWNED!!11!");
	// !!! p1.print();
	Player p3 = "Кетнис Евърдийн";
	// Player p3("Кетнис Евърдийн");
	p3.print();
	// !!! Player p4 = 5;
	anonymousPrint("Фродо");

	std::cin >> p1;
	std::cout << p1;
}

void testDestructor() {
	for(int i = 0; i < 1E8; i++) {
		Player p("Гандалф Сивия", 45);
		p.setScore(50);
		// !!! delete p.getName();
	}

	for(int i = 0; i < 1E8; i++) {
		Player* p = new Player[10];
		delete[] p;
	}

	Player* pa[10];
	for(int i = 0; i < 10; i++) {
		pa[i] = new Player("Орк");
		pa[i]->print();
	}

	delete pa[2];
	delete pa[8];

	for(int i = 0; i < 10; i++)
		if (i != 2 && i != 8)
			delete pa[i];
}

void testInheritance() {
	Player p("Гандалф Сивия", 45);
	Hero h("Кетнис Евърдийн", 50, 3);
	p.print();std::cout << std::endl;
	h.print();std::cout << std::endl;
	std::cout << p;
	std::cout << h;
	Player* p2 = &h;
	p2->print();std::cout << std::endl;
	h.setScore(55);
	p2->print();std::cout << std::endl;
	// !!!
	Hero* h2 = (Hero*)&p;
	h2->print();std::cout << std::endl;
	Hero& h3 = (Hero&)*p2;
	// Hero& h3 = *(Hero*)p2;
	h3.print();std::cout << std::endl;
}

void nl() {
	std::cout << std::endl;
}

Hero* battle(Hero& h1, Hero& h2) {
	if (h1.getLevel() > h2.getLevel())
		return &h1;
	if (h1.getLevel() < h2.getLevel())
		return &h2;
	return nullptr;
}

void fight(Hero& h1, Hero& h2, int prize) {
	std::cout << "Битка между:\n";
	h1.print();nl();
	std::cout << "И\n";
	h2.print();nl();
	Hero* winner = battle(h1, h2);
	if (winner != NULL) {
		winner->setScore(winner->getScore() + prize);
		std::cout << "Победител е:\n";
		winner->print();
	} else
		std::cout << "Няма победител!\n";
}

void testBattle() {
	Player catniss("Кетнис Евърдийн", 50);
	Hero gandalf("Гандалф Сивия", 45, 3);
	SuperHero superman("Супермен", 10, 2, "летене");
	catniss.print();nl();
	gandalf.print();nl();
	superman.print();nl();
	superman.becomeSuperHero();
	superman.print();nl();

	Hero gandalfw; //= gandalf;
	gandalfw = gandalf;
	gandalfw.setName("Гандалф Белия");
	gandalf.print();nl();
	gandalfw.print();nl();

	SuperHero superwoman;// = superman;
	superwoman = superman;
	superwoman.setName("Супержена");
	superwoman.print();nl();
	superman.print();nl();

	superman.stopBeingSuperHero();
	fight(gandalf, superman, 10);
	superman.becomeSuperHero();
	fight(gandalf, superman, 20);
}

/*
class ChessPlayer : public Player {
private:
	int elo;
};
*/

int main() {
	// testPlayer();
	// testDestructor();
	// testInheritance();
	testBattle();

	// ChessPlayer cp;
	return 0;
}

<|endoftext|>


<commit_before>/*
 * LinearAverageProbe.hpp
 *
 *  Created on: Apr 22, 2009
 *      Author: rasmussn
 */

#ifndef LINEARAVERAGEPROBE_HPP_
#define LINEARAVERAGEPROBE_HPP_

#include "LinearActivityProbe.hpp"

namespace PV {

class LinearAverageProbe: public PV::LinearActivityProbe {
public:
   LinearAverageProbe(HyPerCol * hc, PVDimType dim, int f, const char * gifFile);
   LinearAverageProbe(const char * filename, HyPerCol * hc, PVDimType dim, int f, const char * gifFile);
   virtual ~LinearAverageProbe();

   virtual int outputState(float time, PVLayer * l);

protected:
   const char * gifFile;
   FILE * fpGif;
   int * locs;
};

}

#endif /* LINEARAVERAGEPROBE_HPP_ */
<commit_msg>Fixed interface.  outputState() takes a HyPerLayer now, not PVLayer.<commit_after>/*
 * LinearAverageProbe.hpp
 *
 *  Created on: Apr 22, 2009
 *      Author: rasmussn
 */

#ifndef LINEARAVERAGEPROBE_HPP_
#define LINEARAVERAGEPROBE_HPP_

#include "LinearActivityProbe.hpp"

namespace PV {

class LinearAverageProbe: public PV::LinearActivityProbe {
public:
   LinearAverageProbe(HyPerCol * hc, PVDimType dim, int f, const char * gifFile);
   LinearAverageProbe(const char * filename, HyPerCol * hc, PVDimType dim, int f, const char * gifFile);
   virtual ~LinearAverageProbe();

   virtual int outputState(float time, HyPerLayer * l);

protected:
   const char * gifFile;
   FILE * fpGif;
   int * locs;
};

}

#endif /* LINEARAVERAGEPROBE_HPP_ */
<|endoftext|>


<commit_before>#include "KVUtil.h"
#include <QRegExp>
#include <QChar>

//
// Taken from http://stackoverflow.com/a/7047000
// TODO: Change the QRegExp (which is bad) to a QRegularExpression (good).
//
QString unescape(QString str)
{
	QRegExp rx("(\\\\u[0-9a-fA-F]{4})");
	int pos = 0;
	while ((pos = rx.indexIn(str, pos)) != -1)
		str.replace(pos++, 6, QChar(rx.cap(1).right(4).toUShort(0, 16)));

	return str;
}
<commit_msg>use QRegularExpression instead of QRegExp<commit_after>#include "KVUtil.h"
#include <QRegularExpression>
#include <QChar>

//
// Taken from http://stackoverflow.com/a/7047000
//
QString unescape(QString str)
{
	QRegularExpression re("(\\\\u[0-9a-fA-F]{4})");
	QRegularExpressionMatchIterator it = re.globalMatch(str);
	while (it.hasNext())
	{
		QRegularExpressionMatch match = it.next();
		str.replace(match.capturedStart(), match.capturedLength(),
		            QChar(match.captured(1).right(4).toUShort(0, 16)));
	}

	return str;
}
<|endoftext|>


<commit_before>#include "../include/Cluster.hpp"

using namespace std;

Cluster::Cluster(Options options)
{

int symmetric, format, offset;
bool reduceZeroRows, transpose, printCooOrDense;

#if 0
    std::string path2matrix = options.path2data+"/testMat"+to_string(0)+".txt";
    Matrix A;

    symmetric = 0;  // 0-not, 1-lower tr., 2-upper tr.
    format = 1;     // 0-coo, 1-csr, 2-dense
    offset = 0;

    printCooOrDense = true;
    A.readCooFromFile(path2matrix,symmetric,format,offset);
    A.printToFile("modif",0,printCooOrDense);
    A.CSR2COO();
    A.printToFile("modif2",0,printCooOrDense);
    printCooOrDense = true;
    A.printToFile("modif3",0,printCooOrDense);

    return

#endif
//    Matrix B;
//    B = B.CreateCopyFrom(A);
//    B.COO2CSR();
//    B.printToFile("modif3",0,printCooOrDense);
//    bool reduceZeroRows = true;
//    bool transpose = true;
//    B.CSRorCOO2DNS(reduceZeroRows, transpose);
    //
    K.resize(options.n_subdomOnCluster);
//    RegMat.resize(options.n_subdomOnCluster);
    R.resize(options.n_subdomOnCluster);
    rhs.resize(options.n_subdomOnCluster);
    Bc.resize(options.n_subdomOnCluster);
    Bf.resize(options.n_subdomOnCluster);
    Bct.resize(options.n_subdomOnCluster);
//  K_regularized.resize(options.n_subdomOnCluster);
//    Fc_sub.resize(options.n_subdomOnCluster);
//    Gc.resize(options.n_subdomOnCluster);

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*                         READING DATA (TXT)                              */
/*                 matrices in coo format are one-based                    */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

    for (int i = 0 ; i < options.n_subdomOnCluster ; i++){
//        std::cout << "\t\t\t====(" << i+1 << "/" <<
//                   options.n_subdomOnCluster <<")====\n";

        /* K - stiffness matrix */
        string path2matrix = options.path2data+"/K"+to_string(i)+".txt";
        symmetric = 2; format = 1; offset = 1;
        this->K[i].readCooFromFile(path2matrix,symmetric,format,offset);

        /* R - kernel matrix */
        path2matrix = options.path2data+"/R1"+to_string(i)+".txt";
        symmetric = 0; format = 2; offset = 1;
        this->R[i].readCooFromFile(path2matrix,symmetric,format,offset);

//    if (_format == 2){
//    }
//    else{
        /* rhs - right-hand-side vector */
        path2matrix = options.path2data+"/f"+to_string(i)+".txt";
        this->rhs[i].readCooFromFile(path2matrix,this->K[i].n_row);
//
        /* Bf - constraints matrix */
        path2matrix = options.path2data+"/B1"+to_string(i)+".txt";
        symmetric = 0; format = 1; offset = 1;
        this->Bf[i].readCooFromFile(path2matrix,symmetric,format,offset);
//
        /* Bc - constraints matrix */
        path2matrix = options.path2data+"/B0"+to_string(i)+".txt";
        symmetric = 0; format = 1; offset = 1;
        this->Bc[i].readCooFromFile(path2matrix,symmetric,format,offset);

        reduceZeroRows = true;
        transpose = true;
        this->Bct[i] = this->Bc[i];
        this->Bct[i].CSRorCOO2DNS(reduceZeroRows,transpose);

//
//
//        /* Regularization of sing. stiff. mat K*/
//        path2matrix = options.path2data+"/RegMat"+to_string(i)+".txt";
//        this->RegMat[i].readCooFromFile(path2matrix,2,1,0);
//         Matrix::dcsradd(this->K[i], this->RegMat[i], this->K_regularized[i]);
//          this->K_regularized[i].RemoveLower();
  }
//
//
// //      Matrix::testPardiso();
//
//      int  isUpperLowerOrBoth = 2;
// //      for (int i = 0 ; i < options.n_subdomOnCluster ; i++){
// //          Matrix KplusBct;
// //          this->Bct[i].COO2CSR();
// //          this->Bct[i].printToFile("Bct_beforPardiso",i);
// //          this->Bct[i].CSR2DNS(isUpperLowerOrBoth);
// //          this->K_regularized[i].InitializeSolve();
// //          this->K_regularized[i].solve(this->Bct[i], KplusBct);
// //          this->Bct[i].DNS2CSR(isUpperLowerOrBoth);
// //          this->Bct[i].printToFile("Bct_beforPardiso",i);
// //          KplusBct.DNS2CSR(isUpperLowerOrBoth);
// //          KplusBct.printToFile("KplusBct",i);
// //          KplusBct.CSR2COO();
// //          KplusBct.CSR2DNS(isUpperLowerOrBoth);
// //
// //          //      Matrix _Fc_sub;
// //          Matrix::Acsr_mult_Bdns_is_Cdns(this->Bc[i],KplusBct,this->Fc_sub[i]);
// //          this->Fc_sub[i].DNS2CSR(2);
// //          Matrix::Acsr_mult_Bdns_is_Cdns(this->Bc[i],this->R[i],this->Gc[i]);
// //
// //
// //          std::cout << " ++++++     size  +++++     " << KplusBct.adns.size() << "   \n";
// //          for (int ii = 0 ; ii < 20 ; ii ++ ){
// //              std::cout << "  +++++++++++++++  "<< KplusBct.adns[ii] << "   \n";
// //          }
//
//             //   }
//
//                /* dumping matrices */

#if 0
    double *X = new double[this->K[0].n_row_cmprs];
    double *Y = new double[this->K[0].n_row_cmprs];
    for (int i = 0 ; i < this->K[0].n_row_cmprs; i++){
       X[i] = 1;
       Y[i] = 0;
    }
    this->K[0].mv_csr(X,Y,true,1);
    for (int i = 0 ; i < this->K[0].n_row_cmprs; i++){
        printf("%f %f \n", X[i], Y[i]);
    }
#else
    Matrix Y = this->Bct[0];
    printCooOrDense = true;
    Y.printToFile("K_Bct",0,printCooOrDense);

#endif

    for (int i = 0; i < options.n_subdomOnCluster ; i++ ){
        printCooOrDense = true;
        this->K[i].printToFile("K",i,printCooOrDense);
        printCooOrDense = true;
        this->R[i].printToFile("R",i,printCooOrDense);
//
//        printCooOrDense = true;
//        this->Bc[i].printToFile("Bc",i,printCooOrDense);
//        printCooOrDense = true;
//        this->Bf[i].printToFile("Bf",i,printCooOrDense);
//        printCooOrDense = true;
//        this->Bf[i].printToFile("Bct",i,printCooOrDense);

//       this->K_regularized[i].printToFile("K_regularized",i);
//        this->RegMat[i].printToFile("RegMat",i);
     }
//
//
//
//          //    for (int i = 0 ; i < options.n_subdomOnCluster ; i++){
//          //        this->K_regularized[i].FinalizeSolve(i);
//          //    }
//
}
<commit_msg>src/Cluster.cpp: changes just because correction in Matrix.cpp<commit_after>#include "../include/Cluster.hpp"

using namespace std;

Cluster::Cluster(Options options)
{

int symmetric, format, offset;
bool reduceZeroRows, transpose, printCooOrDense;

#if 0
    std::string path2matrix = options.path2data+"/testMat"+to_string(0)+".txt";
    Matrix A;

    symmetric = 0;  // 0-not, 1-lower tr., 2-upper tr.
    format = 1;     // 0-coo, 1-csr, 2-dense
    offset = 0;

    printCooOrDense = true;
    A.readCooFromFile(path2matrix,symmetric,format,offset);
    A.printToFile("modif",0,printCooOrDense);
    A.CSR2COO();
    A.printToFile("modif2",0,printCooOrDense);
    printCooOrDense = true;
    A.printToFile("modif3",0,printCooOrDense);

    return

#endif
//    Matrix B;
//    B = B.CreateCopyFrom(A);
//    B.COO2CSR();
//    B.printToFile("modif3",0,printCooOrDense);
//    bool reduceZeroRows = true;
//    bool transpose = true;
//    B.CSRorCOO2DNS(reduceZeroRows, transpose);
    //
    K.resize(options.n_subdomOnCluster);
//    RegMat.resize(options.n_subdomOnCluster);
    R.resize(options.n_subdomOnCluster);
    rhs.resize(options.n_subdomOnCluster);
    Bc.resize(options.n_subdomOnCluster);
    Bf.resize(options.n_subdomOnCluster);
    Bct.resize(options.n_subdomOnCluster);
//  K_regularized.resize(options.n_subdomOnCluster);
//    Fc_sub.resize(options.n_subdomOnCluster);
//    Gc.resize(options.n_subdomOnCluster);

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*                         READING DATA (TXT)                              */
/*                 matrices in coo format are one-based                    */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

    for (int i = 0 ; i < options.n_subdomOnCluster ; i++){
//        std::cout << "\t\t\t====(" << i+1 << "/" <<
//                   options.n_subdomOnCluster <<")====\n";

        /* K - stiffness matrix */
        string path2matrix = options.path2data+"/K"+to_string(i)+".txt";
        symmetric = 2; format = 1; offset = 1;
        this->K[i].readCooFromFile(path2matrix,symmetric,format,offset);

        /* R - kernel matrix */
        path2matrix = options.path2data+"/R1"+to_string(i)+".txt";
        symmetric = 0; format = 2; offset = 1;
        this->R[i].readCooFromFile(path2matrix,symmetric,format,offset);

//    if (_format == 2){
//    }
//    else{
        /* rhs - right-hand-side vector */
        path2matrix = options.path2data+"/f"+to_string(i)+".txt";
        this->rhs[i].readCooFromFile(path2matrix,this->K[i].n_row);
//
        /* Bf - constraints matrix */
        path2matrix = options.path2data+"/B1"+to_string(i)+".txt";
        symmetric = 0; format = 1; offset = 1;
        this->Bf[i].readCooFromFile(path2matrix,symmetric,format,offset);
//
        /* Bc - constraints matrix */
        path2matrix = options.path2data+"/B0"+to_string(i)+".txt";
        symmetric = 0; format = 1; offset = 1;
        this->Bc[i].readCooFromFile(path2matrix,symmetric,format,offset);

        path2matrix = options.path2data+"/B0"+to_string(i)+".txt";
        symmetric = 0; format = 1; offset = 1;
//        this->Bct[i].readCooFromFile(path2matrix,symmetric,format,offset);
        this->Bct[i] = this->Bc[i];
        reduceZeroRows = true;
        transpose = true;
        this->Bct[i].CSRorCOO2DNS(reduceZeroRows,transpose);

//
//
//        /* Regularization of sing. stiff. mat K*/
//        path2matrix = options.path2data+"/RegMat"+to_string(i)+".txt";
//        this->RegMat[i].readCooFromFile(path2matrix,2,1,0);
//         Matrix::dcsradd(this->K[i], this->RegMat[i], this->K_regularized[i]);
//          this->K_regularized[i].RemoveLower();
  }
//
//
// //      Matrix::testPardiso();
//
//      int  isUpperLowerOrBoth = 2;
// //      for (int i = 0 ; i < options.n_subdomOnCluster ; i++){
// //          Matrix KplusBct;
// //          this->Bct[i].COO2CSR();
// //          this->Bct[i].printToFile("Bct_beforPardiso",i);
// //          this->Bct[i].CSR2DNS(isUpperLowerOrBoth);
// //          this->K_regularized[i].InitializeSolve();
// //          this->K_regularized[i].solve(this->Bct[i], KplusBct);
// //          this->Bct[i].DNS2CSR(isUpperLowerOrBoth);
// //          this->Bct[i].printToFile("Bct_beforPardiso",i);
// //          KplusBct.DNS2CSR(isUpperLowerOrBoth);
// //          KplusBct.printToFile("KplusBct",i);
// //          KplusBct.CSR2COO();
// //          KplusBct.CSR2DNS(isUpperLowerOrBoth);
// //
// //          //      Matrix _Fc_sub;
// //          Matrix::Acsr_mult_Bdns_is_Cdns(this->Bc[i],KplusBct,this->Fc_sub[i]);
// //          this->Fc_sub[i].DNS2CSR(2);
// //          Matrix::Acsr_mult_Bdns_is_Cdns(this->Bc[i],this->R[i],this->Gc[i]);
// //
// //
// //          std::cout << " ++++++     size  +++++     " << KplusBct.adns.size() << "   \n";
// //          for (int ii = 0 ; ii < 20 ; ii ++ ){
// //              std::cout << "  +++++++++++++++  "<< KplusBct.adns[ii] << "   \n";
// //          }
//
//             //   }
//
//                /* dumping matrices */

//for (int i = 0 ; i < this->K.size(); i ++ ){
//    cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
//    cout << "this->Bct[0].i_ptr[k].size() = " << this->Bct[i].n_row_cmprs << endl;
//    cout << "this->Bct[0].j_col[k].size() = " << this->Bct[i].n_col  << endl;
//    cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
//    cout <<"\n";
//
//
//    for (int k = 0; k < this->Bct[i].dense.size(); k++){
//        if (this->Bct[i].dense[k] != 0)
//            cout << this->Bct[i].dense[k] << "/"<< endl;
//    }
//}

#if 0
    double *X = new double[this->K[0].n_row_cmprs];
    double *Y = new double[this->K[0].n_row_cmprs];
    for (int i = 0 ; i < this->K[0].n_row_cmprs; i++){
       X[i] = 1;
       Y[i] = 0;
    }
    this->K[0].mv_csr(X,Y,true,1);
    for (int i = 0 ; i < this->K[0].n_row_cmprs; i++){
        printf("%f %f \n", X[i], Y[i]);
    }
#else
//    Matrix Y = this->Bct[0];
//    printCooOrDense = true;
//    Y.printToFile("K_Bct",0,printCooOrDense);

#endif

    for (int i = 0; i < options.n_subdomOnCluster ; i++ ){
//        printCooOrDense = true;
//        this->K[i].printToFile("K",i,printCooOrDense);
//        printCooOrDense = true;
//        this->R[i].printToFile("R",i,printCooOrDense);
//        printCooOrDense = true;
//        this->Bc[i].printToFile("Bc",i,printCooOrDense);
        printCooOrDense = true;
        this->Bct[i].printToFile("Bct",i,printCooOrDense);
        cout << "        "<< this->Bct[i].l2g_i_coo.size() << "\n";
//        printCooOrDense = true;
//        this->Bf[i].printToFile("Bf",i,printCooOrDense);
//        printCooOrDense = true;
//        this->Bf[i].printToFile("Bct",i,printCooOrDense);

//       this->K_regularized[i].printToFile("K_regularized",i);
//        this->RegMat[i].printToFile("RegMat",i);
     }
//
//
//
//          //    for (int i = 0 ; i < options.n_subdomOnCluster ; i++){
//          //        this->K_regularized[i].FinalizeSolve(i);
//          //    }
//
}
<|endoftext|>


<commit_before>//
//  Context.cpp
//  Cinder-Pipeline
//
//  Created by Jean-Pierre Mouilleseaux on 19 Apr 2014.
//  Copyright 2014 Chorded Constructions. All rights reserved.
//

#include "Context.h"
#include "SourceNode.h"
#include "EffectorNode.h"
#include "cinder/Utilities.h"

using namespace ci;

namespace Cinder { namespace Pipeline {

ContextRef Context::create() {
    return ContextRef(new Context())->shared_from_this();
}

Context::Context() {
}

Context::~Context() {
}

#pragma mark -

void Context::setup(const Vec2i size, int attachments) {
#if defined(DEBUG)
    const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
    cinder::app::console() << "GL_RENDERER: " << renderer << std::endl;
    const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
    cinder::app::console() << "GL_VENDOR: " << vendor << std::endl;
    const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
    cinder::app::console() << "GL_VERSION: " << version << std::endl;
    const char* shadingLanguageVersion = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
    cinder::app::console() << "GL_SHADING_LANGUAGE_VERSION: " << shadingLanguageVersion << std::endl;

    std::string extensionsString = std::string(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
    std::vector<std::string> extensions = split(extensionsString, " ");
    extensions.erase(std::remove_if(extensions.begin(), extensions.end(), [](const std::string& s){ return s.empty(); }));
    cinder::app::console() << "GL_EXTENSIONS: " << std::endl;
    for (const std::string& e : extensions) {
        cinder::app::console() << " " << e << std::endl;
    }

    GLint texSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
    cinder::app::console() << "GL_MAX_TEXTURE_SIZE: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &texSize);
    cinder::app::console() << "GL_MAX_3D_TEXTURE_SIZE: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &texSize);
    cinder::app::console() << "GL_MAX_TEXTURE_IMAGE_UNITS: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &texSize);
    cinder::app::console() << "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &texSize);
    cinder::app::console() << "GL_MAX_COLOR_ATTACHMENTS: " << texSize << std::endl;
    cinder::app::console() << std::string(13, '-') << std::endl;
#endif

//    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
//    if (size.x > texSize) {
//        // TODO - tile horizontally
//        cinder::app::console() << "ERROR - setup width '" << size.x << "' exceeds maximum texture size '" << texSize << "', tiling unimplemented" << std::endl;
//    }
//    if (size.y > texSize) {
//        // TODO - tile vertically
//        cinder::app::console() << "ERROR - setup height '" << size.y << "' exceeds maximum texture size '" << texSize << "', tiling unimplemented" << std::endl;
//    }
//
//    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &texSize);
//    if (attachments > GL_MAX_COLOR_ATTACHMENTS) {
//        cinder::app::console() << "ERROR - number of attachments '" << attachments << "' exceeds '" << texSize << "'" << std::endl;
//    }
//
//    float attachmentMemorySizeMB = size.x * size.y * 4 / 1024 / 1024;
//    float totalSizeMB = attachmentMemorySizeMB * attachments;
//
//    if (gl::isExtensionAvailable("GL_NV_texture_barrier")) {
//        if (texSize >= 2 * size.x && texSize >= size.y) {
//            // TODO - double-wide
//        } else if (texSize >= 2 * size.y && texSize >= size.x) {
//            // TODO - double-tall
//        } else {
//            // TODO - tile
//        }
//    }

    gl::Fbo::Format format;
    format.enableColorBuffer(true, attachments);
    format.enableDepthBuffer(false);

    mFBO = gl::Fbo(size.x, size.y, format);
    mFBO.bindFramebuffer(); {
        GLenum buffers[attachments];
        for (unsigned int idx = 0; idx < attachments; idx++) {
            buffers[idx] = GL_COLOR_ATTACHMENT0 + idx;
        }
        glDrawBuffers(attachments, buffers);
        gl::setViewport(mFBO.getBounds());
        gl::clear();
    } mFBO.unbindFramebuffer();
}

#pragma mark - CONNECTIONS

void Context::connectNodes(const NodeRef& sourceNode, const NodePortRef& sourcePort, const NodeRef& destinationNode, const NodePortRef& destinationPort) {
    // remove from output connections if destination port already connected
    if (mInputConnections[destinationNode].count(destinationPort->getKey()) > 0) {
        std::vector<NodePortConnectionRef> connections = mOutputConnections[sourceNode][sourcePort->getKey()];
        connections.erase(std::remove_if(connections.begin(), connections.end(), [destinationNode](const NodePortConnectionRef& c) {
            return c->getDestinationNode() == destinationNode;
        }), connections.end());
    }

    NodePortConnectionRef connection = NodePortConnection::create(sourceNode, sourcePort->getKey(), destinationNode, destinationPort->getKey());
    mInputConnections[destinationNode][destinationPort->getKey()] = connection;
    mOutputConnections[sourceNode][sourcePort->getKey()].push_back(connection);

    // wipe render stack to force a rebuild
    mRenderStack.clear();
}

void Context::connectNodes(const NodeRef& sourceNode, const std::string& sourceNodePortKey, const NodeRef& destinationNode, const std::string& destinationNodePortKey) {
    NodePortRef sourcePort = sourceNode->getOutputPortForKey(sourceNodePortKey);
    NodePortRef destinationPort = destinationNode->getInputPortForKey(destinationNodePortKey);
    connectNodes(sourceNode, sourcePort, destinationNode, destinationPort);
}

void Context::connectNodes(const NodeRef& sourceNode, const NodeRef& destinationNode) {
    connectNodes(sourceNode, "image", destinationNode, "image");
}

#pragma mark -

gl::Texture& Context::evaluate(const NodeRef& node) {
    // rebuild render stack (flush cache) if the stack is empty or the node changes (cache key)
    if (mRenderStack.size() == 0 || node != mRenderNode) {
        mRenderNode = node;
        BranchRef root = branchForNode(mRenderNode);
        mRenderStack = renderStackForRootBranch(root);
    }

#if defined(DEBUG)
    // ASCII visualization
    cinder::app::console() << std::string(3, '#') << std::endl;
    for (const BranchRef& b : mRenderStack) {
        printBranch(b);
    }
    cinder::app::console() << std::endl;
#endif

    // render branches
    unsigned int outAttachment = 0;

    gl::color(Color::white());

    Area viewport = gl::getViewport();
    gl::setViewport(mFBO.getBounds());
    mFBO.bindFramebuffer(); {
        gl::pushMatrices(); {
            gl::setMatricesWindow(mFBO.getSize(), false);

            // int instead of GLenum for Cinder's FBO bindTexture/getTexture
            std::vector<int> availableAttachments;
            for (unsigned int idx = 0; idx < mFBO.getFormat().getNumColorBuffers(); idx++) {
                availableAttachments.push_back(idx);
            }
            std::map<NodeRef, int> attachmentsMap;

            for (const BranchRef& b : mRenderStack) {
                size_t attachmentIndex = 0;
                outAttachment = availableAttachments.at(attachmentIndex);
                int inAttachment = -1;

                for (size_t nodeIdx = 0; nodeIdx < b->getNodes().size(); nodeIdx++) {
                    // TODO - hoist draw buffer assignment
                    NodeRef n = b->getNodes().at(nodeIdx);
                    SourceNodeRef s = std::dynamic_pointer_cast<SourceNode>(n);
                    if (s) {
                        glDrawBuffer(GL_COLOR_ATTACHMENT0 + outAttachment);

                        FBOImageRef outputFBOImage = FBOImage::create(mFBO, outAttachment);
                        s->render(outputFBOImage);

                        inAttachment = outAttachment;
                    } else {
                        EffectorNodeRef e = std::dynamic_pointer_cast<EffectorNode>(n);
                        if (e) {
                            std::vector<NodePortConnectionRef> connections = getInputConnectionsForNodeWithPortType(n, NodePortType::FBOImage);
                            if (connections.size() == 1) {
                                NodePortConnectionRef c = connections.at(0);
                                // grab attachment from map when appropriate
                                if (inAttachment == -1) {
                                    inAttachment = attachmentsMap[c->getSourceNode()];
                                    attachmentsMap.erase(c->getSourceNode());
                                    availableAttachments.push_back(inAttachment);
                                }
                                FBOImageRef inputFBOImage = FBOImage::create(mFBO, inAttachment);
                                e->setValueForInputPortKey(inputFBOImage, c->getDestinationPortKey());

                                attachmentIndex = (attachmentIndex + 1) % availableAttachments.size();
                                outAttachment = availableAttachments.at(attachmentIndex);
                                glDrawBuffer(GL_COLOR_ATTACHMENT0 + outAttachment);

                                FBOImageRef outputFBOImage = FBOImage::create(mFBO, outAttachment);
                                e->render(outputFBOImage);

                                inAttachment = outAttachment;
                            } else if (connections.size() > 1) {
                                for (const NodePortConnectionRef& c : connections) {
                                    inAttachment = attachmentsMap[c->getSourceNode()];
                                    attachmentsMap.erase(c->getSourceNode());
                                    availableAttachments.push_back(inAttachment);

                                    FBOImageRef inputFBOImage = FBOImage::create(mFBO, inAttachment);
                                    e->setValueForInputPortKey(inputFBOImage, c->getDestinationPortKey());
                                }

                                glDrawBuffer(GL_COLOR_ATTACHMENT0 + outAttachment);

                                FBOImageRef outputFBOImage = FBOImage::create(mFBO, outAttachment);
                                e->render(outputFBOImage);

                                inAttachment = outAttachment;
                            }
                        }
                    }

                    // stash output attachment and accompanying node when branch concludes
                    if (nodeIdx == b->getNodes().size() - 1) {
                        attachmentsMap[n] = outAttachment;
                        availableAttachments.erase(std::find(availableAttachments.begin(), availableAttachments.end(), outAttachment));
                    }
                }
            }
        } gl::popMatrices();
    } mFBO.unbindFramebuffer();
    gl::setViewport(viewport);

    return mFBO.getTexture(outAttachment);
}

#pragma mark -

void Context::printBranch(const BranchRef& branch) {
//    for (const NodeRef& n : branch->getNodes()) {
//        cinder::app::console() << n->getName() << " → ";
//    }
//    cinder::app::console() << " (" << branch->getMaxInputCost() << ")" << std::endl;
    for (const NodeRef& n : branch->getNodes()) {
        if (!std::dynamic_pointer_cast<SourceNode>(n)) {
            cinder::app::console() << " → ";
        }

        std::string name = n->getName();
        name.resize(3, ' ');
        cinder::app::console() << "[" << name << "]";
    }
    cinder::app::console() << " (" << branch->getMaxInputCost() << ")";
    cinder::app::console() << std::endl;
}

BranchRef Context::branchForNode(const NodeRef& node) {
    std::map<NodeRef, BranchRef> branchMap;
    std::deque<NodeRef> nodeStack;

    // create branches
    NodeRef n = node;
    while (n) {
        if (branchMap.count(n) == 0) {
            std::deque<NodeRef> nodes;

            NodeRef n2 = n;
            while (n2) {
                nodes.push_front(n2);

                std::vector<NodePortConnectionRef> connections = getInputConnectionsForNodeWithPortType(n2, NodePortType::FBOImage);
                if (connections.size() == 0) {
                    n2 = nullptr;
                } else if (connections.size() == 1) {
                    NodePortConnectionRef connection = connections.at(0);
                    n2 = connection->getSourceNode();

                    // branch on multiple outputs
                    if (getOutputConnectionsForNodeWithPortType(n2, NodePortType::FBOImage).size() > 1) {
                        nodeStack.push_front(n2);
                        n2 = nullptr;
                    }
                } else if (connections.size() > 1) {
                    // branch on multiple inputs
                    for (const NodePortConnectionRef& c : connections) {
                        nodeStack.push_front(c->getSourceNode());
                    }
                    n2 = nullptr;
                }
            }

            BranchRef branch = Branch::create(nodes);
            branchMap[n] = branch;
        }

        if (nodeStack.empty()) {
            n = nullptr;
        } else {
            n = nodeStack.front();
            nodeStack.pop_front();
        }
    }

    // connect branches
    for (auto& kv : branchMap) {
        BranchRef destinationBranch = kv.second;
        n = destinationBranch->getNodes().front();

        std::vector<NodePortConnectionRef> connections = getInputConnectionsForNodeWithPortType(n, NodePortType::FBOImage);
        for (const NodePortConnectionRef& c : connections) {
            BranchRef sourceBranch = branchMap[c->getSourceNode()];
            destinationBranch->connectInputBranch(sourceBranch);
        }
    }

    return branchMap[node];
}

std::deque<BranchRef> Context::renderStackForRootBranch(const BranchRef& branch) {
    std::deque<BranchRef> renderStack;
    std::deque<BranchRef> branchStack;

    BranchRef b = branch;
    while (b) {
        renderStack.push_front(b);

        std::vector<BranchConnectionRef> inputConnections = b->getInputConnections();
        if (inputConnections.empty()) {
            if (branchStack.empty()) {
                b = nullptr;
            } else {
                b = branchStack.front();
                branchStack.pop_front();
            }
        } else {
            // sort by cost DESC
            std::vector<BranchConnectionRef> sortedInputConnections = inputConnections;
            std::sort(sortedInputConnections.begin(), sortedInputConnections.end(), [](const BranchConnectionRef& c1, const BranchConnectionRef& c2) {
                return c1->getInputCost() > c2->getInputCost();
            });

            // follow cheapest path
            b = sortedInputConnections.back()->getSourceBranch();
            sortedInputConnections.pop_back();

            // push the others
            for (const BranchConnectionRef& c : sortedInputConnections) {
                branchStack.push_front(c->getSourceBranch());
            }
        }
    }

    return renderStack;
}

}}
<commit_msg>skip context setup when possible<commit_after>//
//  Context.cpp
//  Cinder-Pipeline
//
//  Created by Jean-Pierre Mouilleseaux on 19 Apr 2014.
//  Copyright 2014 Chorded Constructions. All rights reserved.
//

#include "Context.h"
#include "SourceNode.h"
#include "EffectorNode.h"
#include "cinder/Utilities.h"

using namespace ci;

namespace Cinder { namespace Pipeline {

ContextRef Context::create() {
    return ContextRef(new Context())->shared_from_this();
}

Context::Context() {
}

Context::~Context() {
}

#pragma mark -

void Context::setup(const Vec2i size, int attachments) {
    // bail if size and attachments are unchanged
    if (mFBO && size == mFBO.getSize() && attachments == mFBO.getFormat().getNumColorBuffers()) {
        return;
    }

#if defined(DEBUG)
    const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
    cinder::app::console() << "GL_RENDERER: " << renderer << std::endl;
    const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
    cinder::app::console() << "GL_VENDOR: " << vendor << std::endl;
    const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
    cinder::app::console() << "GL_VERSION: " << version << std::endl;
    const char* shadingLanguageVersion = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
    cinder::app::console() << "GL_SHADING_LANGUAGE_VERSION: " << shadingLanguageVersion << std::endl;

    std::string extensionsString = std::string(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
    std::vector<std::string> extensions = split(extensionsString, " ");
    extensions.erase(std::remove_if(extensions.begin(), extensions.end(), [](const std::string& s){ return s.empty(); }));
    cinder::app::console() << "GL_EXTENSIONS: " << std::endl;
    for (const std::string& e : extensions) {
        cinder::app::console() << " " << e << std::endl;
    }

    GLint texSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
    cinder::app::console() << "GL_MAX_TEXTURE_SIZE: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &texSize);
    cinder::app::console() << "GL_MAX_3D_TEXTURE_SIZE: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &texSize);
    cinder::app::console() << "GL_MAX_TEXTURE_IMAGE_UNITS: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &texSize);
    cinder::app::console() << "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: " << texSize << std::endl;
    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &texSize);
    cinder::app::console() << "GL_MAX_COLOR_ATTACHMENTS: " << texSize << std::endl;
    cinder::app::console() << std::string(13, '-') << std::endl;
#endif

//    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
//    if (size.x > texSize) {
//        // TODO - tile horizontally
//        cinder::app::console() << "ERROR - setup width '" << size.x << "' exceeds maximum texture size '" << texSize << "', tiling unimplemented" << std::endl;
//    }
//    if (size.y > texSize) {
//        // TODO - tile vertically
//        cinder::app::console() << "ERROR - setup height '" << size.y << "' exceeds maximum texture size '" << texSize << "', tiling unimplemented" << std::endl;
//    }
//
//    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &texSize);
//    if (attachments > GL_MAX_COLOR_ATTACHMENTS) {
//        cinder::app::console() << "ERROR - number of attachments '" << attachments << "' exceeds '" << texSize << "'" << std::endl;
//    }
//
//    float attachmentMemorySizeMB = size.x * size.y * 4 / 1024 / 1024;
//    float totalSizeMB = attachmentMemorySizeMB * attachments;
//
//    if (gl::isExtensionAvailable("GL_NV_texture_barrier")) {
//        if (texSize >= 2 * size.x && texSize >= size.y) {
//            // TODO - double-wide
//        } else if (texSize >= 2 * size.y && texSize >= size.x) {
//            // TODO - double-tall
//        } else {
//            // TODO - tile
//        }
//    }

    gl::Fbo::Format format;
    format.enableColorBuffer(true, attachments);
    format.enableDepthBuffer(false);

    mFBO = gl::Fbo(size.x, size.y, format);
    mFBO.bindFramebuffer(); {
        GLenum buffers[attachments];
        for (unsigned int idx = 0; idx < attachments; idx++) {
            buffers[idx] = GL_COLOR_ATTACHMENT0 + idx;
        }
        glDrawBuffers(attachments, buffers);
        gl::setViewport(mFBO.getBounds());
        gl::clear();
    } mFBO.unbindFramebuffer();
}

#pragma mark - CONNECTIONS

void Context::connectNodes(const NodeRef& sourceNode, const NodePortRef& sourcePort, const NodeRef& destinationNode, const NodePortRef& destinationPort) {
    // remove from output connections if destination port already connected
    if (mInputConnections[destinationNode].count(destinationPort->getKey()) > 0) {
        std::vector<NodePortConnectionRef> connections = mOutputConnections[sourceNode][sourcePort->getKey()];
        connections.erase(std::remove_if(connections.begin(), connections.end(), [destinationNode](const NodePortConnectionRef& c) {
            return c->getDestinationNode() == destinationNode;
        }), connections.end());
    }

    NodePortConnectionRef connection = NodePortConnection::create(sourceNode, sourcePort->getKey(), destinationNode, destinationPort->getKey());
    mInputConnections[destinationNode][destinationPort->getKey()] = connection;
    mOutputConnections[sourceNode][sourcePort->getKey()].push_back(connection);

    // wipe render stack to force a rebuild
    mRenderStack.clear();
}

void Context::connectNodes(const NodeRef& sourceNode, const std::string& sourceNodePortKey, const NodeRef& destinationNode, const std::string& destinationNodePortKey) {
    NodePortRef sourcePort = sourceNode->getOutputPortForKey(sourceNodePortKey);
    NodePortRef destinationPort = destinationNode->getInputPortForKey(destinationNodePortKey);
    connectNodes(sourceNode, sourcePort, destinationNode, destinationPort);
}

void Context::connectNodes(const NodeRef& sourceNode, const NodeRef& destinationNode) {
    connectNodes(sourceNode, "image", destinationNode, "image");
}

#pragma mark -

gl::Texture& Context::evaluate(const NodeRef& node) {
    // rebuild render stack (flush cache) if the stack is empty or the node changes (cache key)
    if (mRenderStack.size() == 0 || node != mRenderNode) {
        mRenderNode = node;
        BranchRef root = branchForNode(mRenderNode);
        mRenderStack = renderStackForRootBranch(root);
    }

#if defined(DEBUG)
    // ASCII visualization
    cinder::app::console() << std::string(3, '#') << std::endl;
    for (const BranchRef& b : mRenderStack) {
        printBranch(b);
    }
    cinder::app::console() << std::endl;
#endif

    // render branches
    unsigned int outAttachment = 0;

    gl::color(Color::white());

    Area viewport = gl::getViewport();
    gl::setViewport(mFBO.getBounds());
    mFBO.bindFramebuffer(); {
        gl::pushMatrices(); {
            gl::setMatricesWindow(mFBO.getSize(), false);

            // int instead of GLenum for Cinder's FBO bindTexture/getTexture
            std::vector<int> availableAttachments;
            for (unsigned int idx = 0; idx < mFBO.getFormat().getNumColorBuffers(); idx++) {
                availableAttachments.push_back(idx);
            }
            std::map<NodeRef, int> attachmentsMap;

            for (const BranchRef& b : mRenderStack) {
                size_t attachmentIndex = 0;
                outAttachment = availableAttachments.at(attachmentIndex);
                int inAttachment = -1;

                for (size_t nodeIdx = 0; nodeIdx < b->getNodes().size(); nodeIdx++) {
                    // TODO - hoist draw buffer assignment
                    NodeRef n = b->getNodes().at(nodeIdx);
                    SourceNodeRef s = std::dynamic_pointer_cast<SourceNode>(n);
                    if (s) {
                        glDrawBuffer(GL_COLOR_ATTACHMENT0 + outAttachment);

                        FBOImageRef outputFBOImage = FBOImage::create(mFBO, outAttachment);
                        s->render(outputFBOImage);

                        inAttachment = outAttachment;
                    } else {
                        EffectorNodeRef e = std::dynamic_pointer_cast<EffectorNode>(n);
                        if (e) {
                            std::vector<NodePortConnectionRef> connections = getInputConnectionsForNodeWithPortType(n, NodePortType::FBOImage);
                            if (connections.size() == 1) {
                                NodePortConnectionRef c = connections.at(0);
                                // grab attachment from map when appropriate
                                if (inAttachment == -1) {
                                    inAttachment = attachmentsMap[c->getSourceNode()];
                                    attachmentsMap.erase(c->getSourceNode());
                                    availableAttachments.push_back(inAttachment);
                                }
                                FBOImageRef inputFBOImage = FBOImage::create(mFBO, inAttachment);
                                e->setValueForInputPortKey(inputFBOImage, c->getDestinationPortKey());

                                attachmentIndex = (attachmentIndex + 1) % availableAttachments.size();
                                outAttachment = availableAttachments.at(attachmentIndex);
                                glDrawBuffer(GL_COLOR_ATTACHMENT0 + outAttachment);

                                FBOImageRef outputFBOImage = FBOImage::create(mFBO, outAttachment);
                                e->render(outputFBOImage);

                                inAttachment = outAttachment;
                            } else if (connections.size() > 1) {
                                for (const NodePortConnectionRef& c : connections) {
                                    inAttachment = attachmentsMap[c->getSourceNode()];
                                    attachmentsMap.erase(c->getSourceNode());
                                    availableAttachments.push_back(inAttachment);

                                    FBOImageRef inputFBOImage = FBOImage::create(mFBO, inAttachment);
                                    e->setValueForInputPortKey(inputFBOImage, c->getDestinationPortKey());
                                }

                                glDrawBuffer(GL_COLOR_ATTACHMENT0 + outAttachment);

                                FBOImageRef outputFBOImage = FBOImage::create(mFBO, outAttachment);
                                e->render(outputFBOImage);

                                inAttachment = outAttachment;
                            }
                        }
                    }

                    // stash output attachment and accompanying node when branch concludes
                    if (nodeIdx == b->getNodes().size() - 1) {
                        attachmentsMap[n] = outAttachment;
                        availableAttachments.erase(std::find(availableAttachments.begin(), availableAttachments.end(), outAttachment));
                    }
                }
            }
        } gl::popMatrices();
    } mFBO.unbindFramebuffer();
    gl::setViewport(viewport);

    return mFBO.getTexture(outAttachment);
}

#pragma mark -

void Context::printBranch(const BranchRef& branch) {
//    for (const NodeRef& n : branch->getNodes()) {
//        cinder::app::console() << n->getName() << " → ";
//    }
//    cinder::app::console() << " (" << branch->getMaxInputCost() << ")" << std::endl;
    for (const NodeRef& n : branch->getNodes()) {
        if (!std::dynamic_pointer_cast<SourceNode>(n)) {
            cinder::app::console() << " → ";
        }

        std::string name = n->getName();
        name.resize(3, ' ');
        cinder::app::console() << "[" << name << "]";
    }
    cinder::app::console() << " (" << branch->getMaxInputCost() << ")";
    cinder::app::console() << std::endl;
}

BranchRef Context::branchForNode(const NodeRef& node) {
    std::map<NodeRef, BranchRef> branchMap;
    std::deque<NodeRef> nodeStack;

    // create branches
    NodeRef n = node;
    while (n) {
        if (branchMap.count(n) == 0) {
            std::deque<NodeRef> nodes;

            NodeRef n2 = n;
            while (n2) {
                nodes.push_front(n2);

                std::vector<NodePortConnectionRef> connections = getInputConnectionsForNodeWithPortType(n2, NodePortType::FBOImage);
                if (connections.size() == 0) {
                    n2 = nullptr;
                } else if (connections.size() == 1) {
                    NodePortConnectionRef connection = connections.at(0);
                    n2 = connection->getSourceNode();

                    // branch on multiple outputs
                    if (getOutputConnectionsForNodeWithPortType(n2, NodePortType::FBOImage).size() > 1) {
                        nodeStack.push_front(n2);
                        n2 = nullptr;
                    }
                } else if (connections.size() > 1) {
                    // branch on multiple inputs
                    for (const NodePortConnectionRef& c : connections) {
                        nodeStack.push_front(c->getSourceNode());
                    }
                    n2 = nullptr;
                }
            }

            BranchRef branch = Branch::create(nodes);
            branchMap[n] = branch;
        }

        if (nodeStack.empty()) {
            n = nullptr;
        } else {
            n = nodeStack.front();
            nodeStack.pop_front();
        }
    }

    // connect branches
    for (auto& kv : branchMap) {
        BranchRef destinationBranch = kv.second;
        n = destinationBranch->getNodes().front();

        std::vector<NodePortConnectionRef> connections = getInputConnectionsForNodeWithPortType(n, NodePortType::FBOImage);
        for (const NodePortConnectionRef& c : connections) {
            BranchRef sourceBranch = branchMap[c->getSourceNode()];
            destinationBranch->connectInputBranch(sourceBranch);
        }
    }

    return branchMap[node];
}

std::deque<BranchRef> Context::renderStackForRootBranch(const BranchRef& branch) {
    std::deque<BranchRef> renderStack;
    std::deque<BranchRef> branchStack;

    BranchRef b = branch;
    while (b) {
        renderStack.push_front(b);

        std::vector<BranchConnectionRef> inputConnections = b->getInputConnections();
        if (inputConnections.empty()) {
            if (branchStack.empty()) {
                b = nullptr;
            } else {
                b = branchStack.front();
                branchStack.pop_front();
            }
        } else {
            // sort by cost DESC
            std::vector<BranchConnectionRef> sortedInputConnections = inputConnections;
            std::sort(sortedInputConnections.begin(), sortedInputConnections.end(), [](const BranchConnectionRef& c1, const BranchConnectionRef& c2) {
                return c1->getInputCost() > c2->getInputCost();
            });

            // follow cheapest path
            b = sortedInputConnections.back()->getSourceBranch();
            sortedInputConnections.pop_back();

            // push the others
            for (const BranchConnectionRef& c : sortedInputConnections) {
                branchStack.push_front(c->getSourceBranch());
            }
        }
    }

    return renderStack;
}

}}
<|endoftext|>