<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	NES Emulator ハンドラー
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018, 2019 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/string_utils.hpp"
#include "emu/log.h"
#include "emu/nes/nes.h"
#include "emu/nes/nesinput.h"
#include "emu/nes/nesstate.h"
#include "emu/nes/nes_pal.h"
#include "emu/cpu/dis6502.hpp"

#include "chip/FAMIPAD.hpp"

extern "C" {
	uint8_t get_fami_pad();
}

namespace emu {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ＮＥＳエミュレーション・クラス
		@param[in]	AUDIO_SAMPLE_RATE	オーディオ・サンプル・レート
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t AUDIO_SAMPLE_RATE>
	class nesemu {

		static const int nes_width_  = 256;
		static const int nes_height_ = 240;
        static const int sample_rate_ = AUDIO_SAMPLE_RATE;
		static const int sample_bits_ = 16;
		static const int audio_len_ = (sample_rate_ / 60) + 1;

		uint16_t		audio_buf_[audio_len_];

		bool			nesrom_;

		cpu::dis6502	disa_;

		uint16_t		mon_val_[3];

		nesinput_t		inp_[2];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクタ
		*/
		//-----------------------------------------------------------------//
		nesemu() noexcept : audio_buf_{ 0 }, nesrom_(false),
			disa_(nes6502_getbyte, nes6502_putbyte),
			mon_val_{ 0 }
		{ }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	オーディオをサポートしない場合「false」
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool start(bool audio_ena = true)
		{
			log_init();
			nes_create(sample_rate_, sample_bits_);

            inp_[0].type = INP_JOYPAD0;
            inp_[0].data = 0;
            input_register(&inp_[0]);
            inp_[1].type = INP_JOYPAD1;
            inp_[1].data = 0;
            input_register(&inp_[1]);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  エミュレーター・ファイルを開く
			@param[in]	filename	ファイル名
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool open(const char* filename)
		{
			if(nes_insert_cart(filename) == 0) {
				nesrom_ = true;
			}
			return nesrom_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  カートリッジが有効か？
			@return 有効なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return nesrom_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  一時停止の取得
			@return 一時停止
		*/
		//-----------------------------------------------------------------//
		bool get_pause() const noexcept {
			const nes_t* t = nes_getcontext();
			return t->pause;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  一時停止
		*/
		//-----------------------------------------------------------------//
		void enable_pause(bool ena = true) noexcept {
			if(!nesrom_) return;

			nes_pause(ena);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  情報取得
			@return 情報テキスト
		*/
		//-----------------------------------------------------------------//
		const char* get_info() noexcept {
			nes_t* t = nes_getcontext();
	   		if(t == nullptr) return nullptr;
			if(t->rominfo == nullptr) return nullptr;
			return rom_getinfo(t->rominfo);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  エミュレーターを終了
		*/
		//-----------------------------------------------------------------//
		void close() noexcept
		{
			if(nesrom_) {
				nes_eject_cart();
				nesrom_ = false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
			@param[in]	org		フレームバッファのアドレス
			@param[in]	xs		フレームバッファのＸ幅
			@param[in]	ys		フレームバッファのＹ幅
		*/
		//-----------------------------------------------------------------//
		void service(void* org, uint32_t xs, uint32_t ys)
		{
			auto nes = nes_getcontext();
			bitmap_t* v = nes->vidbuf;
			const rgb_t* lut = get_palette();
			if(v == nullptr || lut == nullptr) {
				return;
			}

			{
				inp_[0].data = 0;  // Player 1
				inp_[1].data = 0;  // Player 2
				uint8_t pad = get_fami_pad();
				if(chip::on(pad, chip::FAMIPAD_ST::A)) {
					inp_[0].data |= INP_PAD_A;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::B)) {
					inp_[0].data |= INP_PAD_B;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::SELECT)) {
					inp_[0].data |= INP_PAD_SELECT;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::START)) {
					inp_[0].data |= INP_PAD_START;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::UP)) {
					inp_[0].data |= INP_PAD_UP;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::DOWN)) {
					inp_[0].data |= INP_PAD_DOWN;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::LEFT)) {
					inp_[0].data |= INP_PAD_LEFT;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::RIGHT)) {
					inp_[0].data |= INP_PAD_RIGHT;
				}
			}

			uint16_t luttmp[256];
			for(uint32_t i = 0; i < 64; ++i) {
               	uint16_t r = lut[i].r;  // R
				uint16_t g = lut[i].g;  // G
				uint16_t b = lut[i].b;  // B
				// R(5), G(6), B(5)
				luttmp[i] = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
				luttmp[i+128+64] = luttmp[i+128] = luttmp[i+64] = luttmp[i];
			}
			uint16_t* dst = static_cast<uint16_t*>(org);
			dst += ((ys - (nes_height_ - 16)) / 2) * xs;
			const uint8_t* src = v->data;
			src += v->pitch * 16;
			for(int h = 0; h < (nes_height_ - 16); ++h) {
				uint16_t* tmp = dst;
				tmp += (xs - nes_width_) / 2;
				for(int w = 0; w < nes_width_ / 16; ++w) {
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
				}
				src += v->pitch - nes_width_;
				dst += xs;
			}
			if(nesrom_) {
				apu_process(audio_buf_, audio_len_);
				nes_emulate(1);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  オーディオ・バッファの長さを取得
			@return オーディオ・バッファの長さ
		*/
		//-----------------------------------------------------------------//
		uint32_t get_audio_len() const noexcept { return audio_len_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  オーディオ・バッファを取得
			@return オーディオ・バッファのポインター
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_audio_buf() const noexcept { return audio_buf_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ステートのセーブ
			@param[in]	no	スロット番号（０～９）
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool save_state(int no) noexcept {
			if(!nesrom_) return false;
			state_setslot(no);
			return state_save() == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ステートのロード
			@param[in]	no	スロット番号（０～９）
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool load_state(int no) noexcept {
			if(!nesrom_) return false;
			state_setslot(no);
			return state_load() == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ハード・リセット
		*/
		//-----------------------------------------------------------------//
		void reset() noexcept {
			nes_reset(HARD_RESET);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モニター機能
			@param[in]	cmd		コマンド
		*/
		//-----------------------------------------------------------------//
		void monitor(const char* cmd) noexcept {
			char ch;
			uint16_t hexadec = 0;
			bool write = false;
			bool area = false;
			while(1) {
				ch = *cmd++;
				if(ch >= 'a' && ch <= 'z') ch -= 0x20;
				if(ch >= '0' && ch <= '9') {
					mon_val_[0] <<= 4;
					mon_val_[0] |= static_cast<uint16_t>(ch - '0');
					++hexadec;
				} else if(ch >= 'A' && ch <= 'F') {
					mon_val_[0] <<= 4;
					mon_val_[0] |= static_cast<uint16_t>(ch - 'A' + 10);
					++hexadec;
				} else if(ch == 'L') {
					if(hexadec > 0) {
						mon_val_[2] = mon_val_[0];
					}
					for(int i = 0; i < 20; ++i) {
						char tmp[64];
						disa_.disasm(mon_val_[2], tmp, sizeof(tmp));
						utils::str::to_caps(tmp, tmp, sizeof(tmp));
						utils::format("%s\n") % tmp;
						mon_val_[2] = disa_.get_pc();
					}
					hexadec = 0;
					write = false;
					area = false;
				} else if(ch == '.') {
					mon_val_[1] = mon_val_[0];
					write = false;
					area = true;
					hexadec = 0;
				} else if(ch == ':') {
					mon_val_[1] = mon_val_[0];
					write = true;
					area = false;
					hexadec = 0;
				} else if(ch == ' ' || ch == 0) {
					if(write) {
						if(hexadec > 0) {
							nes6502_putbyte(mon_val_[1], mon_val_[0]);
							mon_val_[1]++;
						}
					} else if(ch == 0) {
						uint32_t org = 0;
						uint32_t end = 0;
						if(area) {
							org = mon_val_[1];
							if(hexadec > 0) {
								end = mon_val_[0] + 1;
								if(org > end) end = org;
							} else {
								end = org + 16;
							}
							area = false;
						} else {
							if(hexadec > 0) {
								org = mon_val_[1] = mon_val_[0];
								end = org + 1;
							} else {
								org = end = mon_val_[1];
							}
						}
						while(org < end) {
							char tmp[96];
							auto l = end - org;
							if(l == 0) l = 1;
							else if(l > 16) l = 16;
							org = disa_.dump(org, l, tmp, sizeof(tmp));
							utils::format("%s\n") % tmp;
						 }
						mon_val_[1] = org;
					}
					mon_val_[0] = 0;
					hexadec = 0;
				} else {
					utils::format("%c?\n") % ch;
					hexadec = 0;
					write = false;
					area = false;
				}

				if(ch == 0) break;
			}
		}
	};
}
<commit_msg>Update: cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	NES Emulator ハンドラー
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018, 2019 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/string_utils.hpp"
#include "emu/log.h"
#include "emu/nes/nes.h"
#include "emu/nes/nesinput.h"
#include "emu/nes/nesstate.h"
#include "emu/nes/nes_pal.h"
#include "emu/cpu/dis6502.hpp"

#include "chip/FAMIPAD.hpp"

extern "C" {
	uint8_t get_fami_pad();
}

namespace emu {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ＮＥＳエミュレーション・クラス
		@param[in]	AUDIO_SAMPLE_RATE	オーディオ・サンプル・レート
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t AUDIO_SAMPLE_RATE>
	class nesemu {

		static const int nes_width_  = 256;
		static const int nes_height_ = 240;
        static const int sample_rate_ = AUDIO_SAMPLE_RATE;
		static const int sample_bits_ = 16;
		static const int audio_len_ = (sample_rate_ / 60) + 1;

		uint16_t		audio_buf_[audio_len_];

		bool			nesrom_;

		cpu::dis6502	disa_;

		uint16_t		mon_val_[3];

		nesinput_t		inp_[2];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクタ
		*/
		//-----------------------------------------------------------------//
		nesemu() noexcept : audio_buf_{ 0 }, nesrom_(false),
			disa_(nes6502_getbyte, nes6502_putbyte),
			mon_val_{ 0 }
		{ }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	オーディオをサポートしない場合「false」
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool start(bool audio_ena = true)
		{
			log_init();
			nes_create(sample_rate_, sample_bits_);

            inp_[0].type = INP_JOYPAD0;
            inp_[0].data = 0;
            input_register(&inp_[0]);
            inp_[1].type = INP_JOYPAD1;
            inp_[1].data = 0;
            input_register(&inp_[1]);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  エミュレーター・ファイルを開く
			@param[in]	filename	ファイル名
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool open(const char* filename)
		{
			if(nes_insert_cart(filename) == 0) {
				nesrom_ = true;
			}
			return nesrom_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  カートリッジが有効か？
			@return 有効なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return nesrom_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  一時停止の取得
			@return 一時停止
		*/
		//-----------------------------------------------------------------//
		bool get_pause() const noexcept {
			const nes_t* t = nes_getcontext();
			return t->pause;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  一時停止
		*/
		//-----------------------------------------------------------------//
		void enable_pause(bool ena = true) noexcept {
			if(!nesrom_) return;

			nes_pause(ena);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  情報取得
			@return 情報テキスト
		*/
		//-----------------------------------------------------------------//
		const char* get_info() noexcept {
			nes_t* t = nes_getcontext();
	   		if(t == nullptr) return nullptr;
			if(t->rominfo == nullptr) return nullptr;
			return rom_getinfo(t->rominfo);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  エミュレーターを終了
		*/
		//-----------------------------------------------------------------//
		void close() noexcept
		{
			if(nesrom_) {
				nes_eject_cart();
				nesrom_ = false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
			@param[in]	org		フレームバッファのアドレス
			@param[in]	xs		フレームバッファのＸ幅
			@param[in]	ys		フレームバッファのＹ幅
		*/
		//-----------------------------------------------------------------//
		void service(void* org, uint32_t xs, uint32_t ys)
		{
			auto nes = nes_getcontext();
			bitmap_t* v = nes->vidbuf;
			const rgb_t* lut = get_palette();
			if(v == nullptr || lut == nullptr) {
				return;
			}

			{
				inp_[0].data = 0;  // Player 1
				inp_[1].data = 0;  // Player 2
				uint8_t pad = get_fami_pad();
				if(chip::on(pad, chip::FAMIPAD_ST::A)) {
					inp_[0].data |= INP_PAD_A;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::B)) {
					inp_[0].data |= INP_PAD_B;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::SELECT)) {
					inp_[0].data |= INP_PAD_SELECT;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::START)) {
					inp_[0].data |= INP_PAD_START;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::UP)) {
					inp_[0].data |= INP_PAD_UP;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::DOWN)) {
					inp_[0].data |= INP_PAD_DOWN;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::LEFT)) {
					inp_[0].data |= INP_PAD_LEFT;
				}
				if(chip::on(pad, chip::FAMIPAD_ST::RIGHT)) {
					inp_[0].data |= INP_PAD_RIGHT;
				}
			}

			uint16_t luttmp[256];
			for(uint32_t i = 0; i < 64; ++i) {
               	uint16_t r = lut[i].r;  // R
				uint16_t g = lut[i].g;  // G
				uint16_t b = lut[i].b;  // B
				// R(5), G(6), B(5)
				luttmp[i] = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3);
				luttmp[i+128+64] = luttmp[i+128] = luttmp[i+64] = luttmp[i];
			}
			uint16_t* dst = static_cast<uint16_t*>(org);
			dst += ((ys - (nes_height_ - 16)) / 2) * xs;
			const uint8_t* src = v->data;
			src += v->pitch * 16;
			for(int h = 0; h < (nes_height_ - 16); ++h) {
				uint16_t* tmp = dst;
				tmp += (xs - nes_width_) / 2;
				for(int w = 0; w < nes_width_ / 16; ++w) {
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
					*tmp++ = luttmp[*src++]; *tmp++ = luttmp[*src++];
				}
				src += v->pitch - nes_width_;
				dst += xs;
			}
			if(nesrom_) {
				apu_process(audio_buf_, audio_len_);
				nes_emulate(1);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  オーディオ・バッファの長さを取得
			@return オーディオ・バッファの長さ
		*/
		//-----------------------------------------------------------------//
		uint32_t get_audio_len() const noexcept { return audio_len_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  オーディオ・バッファを取得
			@return オーディオ・バッファのポインター
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_audio_buf() const noexcept { return audio_buf_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ステートのセーブ
			@param[in]	no	スロット番号（０～９）
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool save_state(int no) noexcept {
			if(!nesrom_) return false;
			state_setslot(no);
			return state_save() == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ステートのロード
			@param[in]	no	スロット番号（０～９）
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool load_state(int no) noexcept {
			if(!nesrom_) return false;
			state_setslot(no);
			return state_load() == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ハード・リセット
		*/
		//-----------------------------------------------------------------//
		void reset() noexcept {
			nes_reset(HARD_RESET);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モニター機能
			@param[in]	cmd		コマンド
		*/
		//-----------------------------------------------------------------//
		void monitor(const char* cmd) noexcept {
			char ch;
			uint16_t hexadec = 0;
			bool write = false;
			bool area = false;
			bool search = false;
			while(1) {
				ch = *cmd++;
				if(ch >= 'a' && ch <= 'z') ch -= 0x20;
				if(ch >= '0' && ch <= '9') {
					mon_val_[0] <<= 4;
					mon_val_[0] |= static_cast<uint16_t>(ch - '0');
					++hexadec;
				} else if(ch >= 'A' && ch <= 'F') {
					mon_val_[0] <<= 4;
					mon_val_[0] |= static_cast<uint16_t>(ch - 'A' + 10);
					++hexadec;
				} else if(ch == 'L') {  ///< disasm List
					if(hexadec > 0) {
						mon_val_[2] = mon_val_[0];
					}
					for(int i = 0; i < 20; ++i) {
						char tmp[64];
						disa_.disasm(mon_val_[2], tmp, sizeof(tmp));
						utils::str::to_caps(tmp, tmp, sizeof(tmp));
						utils::format("%s\n") % tmp;
						mon_val_[2] = disa_.get_pc();
					}
					hexadec = 0;
					write = false;
					area = false;
				} else if(ch == 'S') {  ///< Search
					mon_val_[2] = mon_val_[0];
					search = true;
					hexadec = 0;
				} else if(ch == '.') {
					mon_val_[1] = mon_val_[0];
					write = false;
					area = true;
					hexadec = 0;
				} else if(ch == ':') {
					mon_val_[1] = mon_val_[0];
					write = true;
					area = false;
					hexadec = 0;
				} else if(ch == ' ' || ch == 0) {
					if(write) {
						if(hexadec > 0) {
							nes6502_putbyte(mon_val_[1], mon_val_[0]);
							mon_val_[1]++;
						}
					} else if(ch == 0) {
						uint32_t org = 0;
						uint32_t end = 0;
						if(search) {  // search
							org = mon_val_[1];
							end = mon_val_[2];
							while(org <= end) {
								auto rd = nes6502_getbyte(org);
								if(rd == (mon_val_[0] & 0xff)) {
									utils::format("%04X- %02X\n") % org % static_cast<uint16_t>(rd);
								}
								++org;
							}
						} else {  // for dump
							if(area) {
								org = mon_val_[1];
								if(hexadec > 0) {
									end = mon_val_[0] + 1;
									if(org > end) end = org;
								} else {
									end = org + 16;
								}
								area = false;
							} else {
								if(hexadec > 0) {
									org = mon_val_[1] = mon_val_[0];
									end = org + 1;
								} else {
									org = end = mon_val_[1];
								}
							}
							while(org < end) {
								char tmp[96];
								auto l = end - org;
								if(l == 0) l = 1;
								else if(l > 16) l = 16;
								org = disa_.dump(org, l, tmp, sizeof(tmp));
								utils::format("%s\n") % tmp;
							 }
							mon_val_[1] = org;
						}
					}
					mon_val_[0] = 0;
					hexadec = 0;
				} else {
					utils::format("%c?\n") % ch;
					hexadec = 0;
					write = false;
					area = false;
					search = false;
				}

				if(ch == 0) break;
			}
		}
	};
}
<|endoftext|>


<commit_before>#include "TestCommon.hh" //to get argparser

using namespace SDLut;

Logger testlog("ScreenAccess");

class Assert : public AssertEngine
{
    video::Rect assertedrect;
    video::Color color;
public:
    Assert(Logger& l, ArgParser& ap,video::Rect assertrect, video::Color c)
            : AssertEngine(l,ap), assertedrect(assertrect), color(c)
    {
        if ( ! testlog.isFileLogEnabled() ) testlog.enableFileLog("TestScreenAccess.log");
    }

    bool assertresize(int width, int height)
    {
        if (assertedrect.getx() < 0) assertedrect.resetx(0);
        if (assertedrect.gety() < 0) assertedrect.resety(0);
        if ( (int)(assertedrect.getx() + assertedrect.getw() ) > width ) assertedrect.resetw( width - assertedrect.getx() );
        if ( (int)(assertedrect.gety() + assertedrect.geth() ) > height ) assertedrect.reseth( height - assertedrect.gety() );

        return true;
    }
    bool assertrender(video::ScreenBuffer& sb) const
    {
        bool res = true;
        int x =assertedrect.getx(), y =assertedrect.gety();
        while ( y < (int)assertedrect.geth())
        {
            while ( x < (int)assertedrect.getw() )
            {
                res = res && (sb.getColorAt(x,y) == color);
            }
        }

        return res ;
    }
};

class Test : public TestEngine
{
    video::Rect testedrect;
    video::Color color;
public:

    Test(Logger& l, Assert & a, video::Rect testrect, video::Color c) : TestEngine(l,a), testedrect(testrect),color(c) {}
    bool resize(int width, int height)
    {
        //check rect size
        if (testedrect.getx() < 0) testedrect.resetx(0);
        if (testedrect.gety() < 0) testedrect.resety(0);
        if ( (int)(testedrect.getx() + testedrect.getw()) > width ) testedrect.resetw( width - testedrect.getx() );
        if ( (int)(testedrect.gety() + testedrect.geth()) > height ) testedrect.reseth( height - testedrect.gety() );

        return true;
    }
    bool render(video::ScreenBuffer& sb) const
    {
        if ( (1 == testedrect.geth() ) && ( testedrect.getw() == 1 ) )
        {
            sb.setColorAt( testedrect.getx(),testedrect.gety(),color );
        }
        else
        {
            //working around constness
            video::Rect dstrect = testedrect;
            sb.setColorAt( dstrect,color);
        }

        return true;
    }
};

int main(int argc, char** argv)
{
    ArgParser args(argc,argv);

    //Starting with usual SDL window
    App::getInstance().initVideo(false,true,false);
    App::getInstance().setName ("SDLut::video Dumb test ");

    //Setting Display size and BPP
    App::getInstance().getDisplay().requestSize(300,240); // using autodetected bpp
    App::getInstance().getDisplay().requestOpenGL(args.isOGL());

    int exitstatus = -1;

    ///testing pixel set
    video::Color color(Randomizer<unsigned char>::get(),Randomizer<unsigned char>::get(),Randomizer<unsigned char>::get());
    video::Rect pix(Randomizer<unsigned int>::get(0,300),Randomizer<unsigned int>::get(0,240 - 64 )); //keeping some space for logos...

    Assert asrt(testlog,args,pix,color);
    Test engine(testlog,asrt,pix,color);

    if (App::getInstance().getDisplay().show())
    {
        exitstatus = App::getInstance().getDisplay().mainLoop();
    }

    video::Rect scarea(Randomizer<unsigned int>::get(0,300),Randomizer<unsigned int>::get(0,240 - 64 )); //keeping some space for logos...
    scarea.resetw(Randomizer<unsigned int>::get(1,300 - scarea.getx()));
    scarea.reseth(Randomizer<unsigned int>::get(1,240-64 - scarea.gety()));

    //quick check
    if (scarea.getw() < 1)
    {
        scarea.resetw();
    }
    if (scarea.geth() < 1)
    {
        scarea.reseth();
    }

    ///testing rect fill

    //Declaring these here will construct them and reset the SDLut Callbacks as per parents classes in TestCommon.hh.
    Assert asrtbis(testlog,args,scarea,color);
    Test enginebis(testlog,asrtbis,scarea,color);

    //BUG
    //This should not be needed !!!
    //TODO : FIX IT
    App::getInstance().getDisplay().requestOpenGL(args.isOGL());
    if (App::getInstance().getDisplay().show())
    {
        exitstatus = (exitstatus == 0) && App::getInstance().getDisplay().mainLoop();
    }

    return exitstatus;
}

<commit_msg>fix for midnight coding syndrome...<commit_after>#include "TestCommon.hh" //to get argparser

using namespace SDLut;

Logger testlog("ScreenAccess");

class Assert : public AssertEngine
{
    video::Rect assertedrect;
    video::Color color;
public:
    Assert(Logger& l, ArgParser& ap,video::Rect assertrect, video::Color c)
            : AssertEngine(l,ap), assertedrect(assertrect), color(c)
    {
        if ( ! testlog.isFileLogEnabled() ) testlog.enableFileLog("TestScreenAccess.log");
    }

    bool assertresize(int width, int height)
    {
        if (assertedrect.getx() < 0) assertedrect.resetx(0);
        if (assertedrect.gety() < 0) assertedrect.resety(0);
        if ( (int)(assertedrect.getx() + assertedrect.getw() ) > width ) assertedrect.resetw( width - assertedrect.getx() );
        if ( (int)(assertedrect.gety() + assertedrect.geth() ) > height ) assertedrect.reseth( height - assertedrect.gety() );

        return true;
    }
    bool assertrender(video::ScreenBuffer& sb) const
    {
        bool res = true;
        unsigned int x =0, y =0;
        while ( y < assertedrect.geth())
        {
            while ( x < assertedrect.getw())
            {
                res = res && (sb.getColorAt(x + assertedrect.getx(),y + assertedrect.gety()) == color);
                x++;
            }
            y++;
        }

        return res ;
    }
};

class Test : public TestEngine
{
    video::Rect testedrect;
    video::Color color;
public:

    Test(Logger& l, Assert & a, video::Rect testrect, video::Color c) : TestEngine(l,a), testedrect(testrect),color(c) {}
    bool resize(int width, int height)
    {
        //check rect size
        if (testedrect.getx() < 0) testedrect.resetx(0);
        if (testedrect.gety() < 0) testedrect.resety(0);
        if ( (int)(testedrect.getx() + testedrect.getw()) > width ) testedrect.resetw( width - testedrect.getx() );
        if ( (int)(testedrect.gety() + testedrect.geth()) > height ) testedrect.reseth( height - testedrect.gety() );

        return true;
    }
    bool render(video::ScreenBuffer& sb) const
    {
        if ( (1 == testedrect.geth() ) && ( testedrect.getw() == 1 ) )
        {
            sb.setColorAt( testedrect.getx(),testedrect.gety(),color );
        }
        else
        {
            //working around constness
            video::Rect dstrect = testedrect;
            sb.setColorAt( dstrect,color);
        }

        return true;
    }
};

int main(int argc, char** argv)
{
    ArgParser args(argc,argv);

    //Starting with usual SDL window
    App::getInstance().initVideo(false,true,false);
    App::getInstance().setName ("SDLut::video Dumb test ");

    //Setting Display size and BPP
    App::getInstance().getDisplay().requestSize(300,240); // using autodetected bpp
    App::getInstance().getDisplay().requestOpenGL(args.isOGL());

    int exitstatus = -1;

    ///testing pixel set
    video::Color color(Randomizer<unsigned char>::get(),Randomizer<unsigned char>::get(),Randomizer<unsigned char>::get());
    video::Rect pix(Randomizer<unsigned int>::get(0,300),Randomizer<unsigned int>::get(0,240 - 64 )); //keeping some space for logos...

    Assert asrt(testlog,args,pix,color);
    Test engine(testlog,asrt,pix,color);

    if (App::getInstance().getDisplay().show())
    {
        exitstatus = App::getInstance().getDisplay().mainLoop();
    }

    video::Rect scarea(Randomizer<unsigned int>::get(0,300),Randomizer<unsigned int>::get(0,240 - 64 )); //keeping some space for logos...
    scarea.resetw(Randomizer<unsigned int>::get(1,300 - scarea.getx()));
    scarea.reseth(Randomizer<unsigned int>::get(1,240-64 - scarea.gety()));

    //quick check
    if (scarea.getw() < 1)
    {
        scarea.resetw();
    }
    if (scarea.geth() < 1)
    {
        scarea.reseth();
    }

    ///testing rect fill

    //Declaring these here will construct them and reset the SDLut Callbacks as per parents classes in TestCommon.hh.
    Assert asrtbis(testlog,args,scarea,color);
    Test enginebis(testlog,asrtbis,scarea,color);

    //BUG
    //This should not be needed !!!
    //TODO : FIX IT
    App::getInstance().getDisplay().requestOpenGL(args.isOGL());
    if (App::getInstance().getDisplay().show())
    {
        exitstatus = (exitstatus == 0) && App::getInstance().getDisplay().mainLoop();
    }

    return exitstatus;
}

<|endoftext|>


<commit_before>//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
#define CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_

#include "clotho/data_spaces/crossover/crossover_method_def.hpp"
#include "clotho/data_spaces/association_matrix/row_grouped_association_matrix.hpp"

#include "clotho/data_spaces/generators/small_crossover_event_generator.hpp"
#include "clotho/data_spaces/generators/buffered_small_crossover_event_generator.hpp"
#include "clotho/utility/bit_helper.hpp"
#include "clotho/utility/debruijn_bit_walker.hpp"

namespace clotho {
namespace genetics {

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 2 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 2 > >     sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef small_crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.getPositions(), alls.size());
    }

    void crossover( genome_iterator start, genome_iterator end, sequence_iterator s, size_t p_step, size_t s_step ) {

        size_t N = m_event_gen.generate();

        if( N != 0 ) {
            size_t j = 0;
            while( start != end ) {
                block_type first = *start++;
                block_type second = *start++;

                block_type hets = first ^ second;
                block_type sec  = bit_helper_type::ALL_UNSET;   // mask state from second strand

                while( hets ) {
                    size_t idx = bit_walker_type::unset_next_index( hets ) + j;

                    if( m_event_gen( idx ) ) {
                        sec |= bit_helper_type::bit_offset( idx );
                    }
                }

                *s = ((first & ~sec) | (second & sec));

                j += bit_helper_type::BITS_PER_BLOCK;

                s += row_grouped< 2 >::GROUP_SIZE;
            }
        } else {
            if( m_event_gen.getBaseSequence() != 0 ) {

                ++start;
                ++end;
            }

            size_t j = 0;
            while( start != end ) {
                *s = *start;

                start += row_grouped< 2 >::GROUP_SIZE;
                s += row_grouped< 2 >::GROUP_SIZE;

                j += bit_helper_type::BITS_PER_BLOCK;
            }
        }
    }

    virtual ~crossover_method() {}

protected:
    event_generator_type m_event_gen;
};

template < class BlockType >
struct base_crossover_method {
    inline BlockType operator()( const BlockType & a, const BlockType & b, const BlockType & c) const {
        return ((a & ~c) | (b & c));
    }
};

template < class BlockType >
struct alt_crossover_method {
    inline BlockType operator()( const BlockType & a, const BlockType & b, const BlockType & c) const {
        return ((a & c) | (b & ~c));
    }
};

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 1 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 1 > >   sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef buffered_small_crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    typedef base_crossover_method< block_type >                 base_method;
    typedef alt_crossover_method< block_type >                  alt_method;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.getPositions(), alls.size() );
    }

/**
 *
 * @return soft max of result sequence
 */
    unsigned int crossover( sequence_iterator first, unsigned int N, sequence_iterator second, unsigned int M, sequence_iterator s ) {
        unsigned int res = 0;
        if( m_event_gen.generate() != 0 ) {
            if( m_event_gen.getBaseSequence() == 0 ) {
                base_method met;
                res = buffered_write_build_sequence( s, first, N, second, M, met );
            } else {
                alt_method met;
                res = buffered_write_build_sequence(s, first, N, second, M, met );
            }
        } else if( m_event_gen.getBaseSequence() != 0 ) {
            // use second strand
            res = copy_sequence( s, second, M );
        } else {
            res = copy_sequence( s, first, N );
        }

        return res;
    }

    virtual ~crossover_method() {}

protected:

/**
 *
 * Copies global sequence data to local stack buffers
 * Operates on stack buffers writing back to stack
 * Copies stack to final output vector
 *
 * Is read and write buffering beneficial?
 *
 * @return soft max of result sequence
 */
    template < class Method >
    unsigned int buffered_build_sequence( sequence_iterator res, sequence_iterator first, const unsigned int soft_N, sequence_iterator second, const unsigned int soft_M, const Method & m ) {
        const unsigned int N = 16;
        block_type first_buffer[ N ];   // 16 * 8 == 128 byte buffer
        block_type second_buffer[ N ];

        const unsigned int soft_max = (( soft_N > soft_M )? soft_N : soft_M );   // soft maximum length
        unsigned int last_block = 0;

        unsigned int l = 0;
        while( l < soft_max ) {
            unsigned int j = (soft_max - l);
            j = ((j > N) ? N : j);

            // read global data to local buffers
            memcpy( first_buffer, first + l, j * sizeof( block_type ) );
            memcpy( second_buffer, second + l, j * sizeof( block_type ) );

            unsigned int i = 0;
            while( i < j ) {
                const unsigned int offset = l + i;
                block_type first = ((offset < soft_N ) ? first_buffer[ i ] : bit_helper_type::ALL_UNSET);
                block_type second = ((offset < soft_M ) ? second_buffer[ i ] : bit_helper_type::ALL_UNSET);

                block_type mask = buffered_build_mask( first, second, offset * bit_helper_type::BITS_PER_BLOCK );

                mask = m( first, second, mask );
                second_buffer[ i ] = mask;
                ++i;
                if( mask ) {
                    last_block = offset + 1;
                }
            }

            // write to result sequence
            memcpy( res + l, second_buffer, j * sizeof(block_type) );
            l += j;
        }

        return last_block;
    }

/**
 * Unraveled the set bit decoding
 */
    block_type buffered_build_mask( block_type first, block_type second, unsigned int offset ) {
        block_type hets = first ^ second;
        block_type mask  = bit_helper_type::ALL_UNSET;   // mask state from second strand

        unsigned int het_buffer[ bit_helper_type::BITS_PER_BLOCK ]; // i.e. buffer_size = 64 * 4 = 256 bytes buffer

        if( hets ) {
            m_event_gen.update_buffer( offset );

            // decode set indices
            unsigned int j = 0;
            do {
                het_buffer[ j ] = bit_walker_type::unset_next_index( hets );
                ++j;
            } while( hets );

            // evaluate positions at relative indices
            unsigned int i = 0;
            while( i < j ) {
                unsigned int idx = het_buffer[ i ];
                if( m_event_gen( idx ) ) {
                    mask |= clotho::utility::bit_masks[ idx ];
                }
                ++i;
            }
        }

        return mask;
    }

/**
 *
 * Initial technique for building a crossover mask
 *
 *
 */
    block_type build_mask( block_type first, block_type second, unsigned int offset ) {
        block_type hets = first ^ second;
        block_type mask = bit_helper_type::ALL_UNSET;   // mask state from second strand

        if( hets ) {
            m_event_gen.update_buffer( offset );

            do {
                unsigned int idx = bit_walker_type::unset_next_index( hets );

                if( m_event_gen( idx ) ) {
                    mask |= clotho::utility::bit_masks[ idx ];
                }
            } while( hets );
        }

        return mask;
    }

    template < class Method >
    void build_sequence( sequence_iterator s, genome_iterator start, genome_iterator end, const Method & m ) {
        size_t j = 0;
        genome_iterator sec_ptr = end;
        while( start != end ) {
            block_type first = *start++;
            block_type second = *sec_ptr++;

            block_type mask = build_mask( first, second, j );

            *s++ = m(first, second, mask);

            j += bit_helper_type::BITS_PER_BLOCK;
        }
    }

/**
 *
 * Uses soft max of both sequence
 *
 * Is write buffer beneficial?
 *
 * @return soft max of result sequence
 */
    template < class Method >
    unsigned int buffered_write_build_sequence( sequence_iterator res, sequence_iterator first, const unsigned int soft_N, sequence_iterator second, const unsigned int soft_M, const Method & m ) {

        const unsigned int N = 32;
        block_type  _buffer[ N ];   // 256 byte buffer

        const unsigned int soft_max = (( soft_N > soft_M )? soft_N : soft_M );   // soft maximum length
        unsigned int last_block = 0;

        unsigned int i = 0, j = 0;

        while( j < soft_max ) {
            block_type a = ((j < soft_N ) ? first[ j ] : bit_helper_type::ALL_UNSET);
            block_type b = ((j < soft_M ) ? second[ j ] : bit_helper_type::ALL_UNSET);

            block_type mask = build_mask( a, b, j * bit_helper_type::BITS_PER_BLOCK );

            mask = m( a, b, mask );
            _buffer[ i++ ] = mask;
            ++j;

            if( mask ) {
                last_block = j;
            }

            if( i >= N ) {
                // buffer is full
                memcpy( res, _buffer, N * sizeof(block_type) );
                res += N;
                i = 0;
            }
        }

        // write final buffer
        if( i ) {
            memcpy( res, _buffer, i * sizeof( block_type ) );
        }

        return last_block;
    }

/**
 *
 *
 * @return soft max of result sequence
 */
    template < class Method >
    unsigned int build_sequence( sequence_iterator res, sequence_iterator first, const unsigned int N, sequence_iterator second, const unsigned int M, const Method & m ) {

        const unsigned int W = (( N > M )? N : M );
        unsigned int i = 0;
        unsigned int last_block = 0;
        while( i < W ) {
            block_type a = ((i < N ) ? first[ i ] : bit_helper_type::ALL_UNSET);
            block_type b = ((i < M ) ? second[ i ] : bit_helper_type::ALL_UNSET);

            block_type mask = build_mask( a, b, i * bit_helper_type::BITS_PER_BLOCK );

            mask = m(a, b, mask );
            res[ i ] = mask;
            ++i;

            if( mask ) {
                last_block = i;
            }
        }

        return last_block;
    }

    unsigned int copy_sequence( sequence_iterator s, sequence_iterator start, const size_t W ) {
        memcpy( s, start, W * sizeof(block_type));
        return W;
    }

    event_generator_type m_event_gen;
};

}   // namespace genetics
}   // namespace clotho

#endif  // CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
<commit_msg>Attempting something more efficient<commit_after>//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
#define CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_

#include "clotho/data_spaces/crossover/crossover_method_def.hpp"
#include "clotho/data_spaces/association_matrix/row_grouped_association_matrix.hpp"

#include "clotho/data_spaces/generators/small_crossover_event_generator.hpp"
#include "clotho/data_spaces/generators/buffered_small_crossover_event_generator.hpp"
#include "clotho/utility/bit_helper.hpp"
#include "clotho/utility/debruijn_bit_walker.hpp"

namespace clotho {
namespace genetics {

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 2 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 2 > >     sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef small_crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.getPositions(), alls.size());
    }

    void crossover( genome_iterator start, genome_iterator end, sequence_iterator s, size_t p_step, size_t s_step ) {

        size_t N = m_event_gen.generate();

        if( N != 0 ) {
            size_t j = 0;
            while( start != end ) {
                block_type first = *start++;
                block_type second = *start++;

                block_type hets = first ^ second;
                block_type sec  = bit_helper_type::ALL_UNSET;   // mask state from second strand

                while( hets ) {
                    size_t idx = bit_walker_type::unset_next_index( hets ) + j;

                    if( m_event_gen( idx ) ) {
                        sec |= bit_helper_type::bit_offset( idx );
                    }
                }

                *s = ((first & ~sec) | (second & sec));

                j += bit_helper_type::BITS_PER_BLOCK;

                s += row_grouped< 2 >::GROUP_SIZE;
            }
        } else {
            if( m_event_gen.getBaseSequence() != 0 ) {

                ++start;
                ++end;
            }

            size_t j = 0;
            while( start != end ) {
                *s = *start;

                start += row_grouped< 2 >::GROUP_SIZE;
                s += row_grouped< 2 >::GROUP_SIZE;

                j += bit_helper_type::BITS_PER_BLOCK;
            }
        }
    }

    virtual ~crossover_method() {}

protected:
    event_generator_type m_event_gen;
};

template < class BlockType >
struct base_crossover_method {
    inline BlockType operator()( const BlockType & a, const BlockType & b, const BlockType & c) const {
        return ((a & ~c) | (b & c));
    }
};

template < class BlockType >
struct alt_crossover_method {
    inline BlockType operator()( const BlockType & a, const BlockType & b, const BlockType & c) const {
        return ((a & c) | (b & ~c));
    }
};

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 1 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 1 > >   sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef small_crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    typedef base_crossover_method< block_type >                 base_method;
    typedef alt_crossover_method< block_type >                  alt_method;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.getPositions(), alls.size() );
    }

/**
 *
 * @return soft max of result sequence
 */
    unsigned int crossover( sequence_iterator first, unsigned int N, sequence_iterator second, unsigned int M, sequence_iterator s ) {
        unsigned int res = 0;
        if( m_event_gen.generate() != 0 ) {
            if( m_event_gen.getBaseSequence() == 0 ) {
                base_method met;
                res = build_sequence( s, first, N, second, M, met );
            } else {
                alt_method met;
                res = build_sequence(s, first, N, second, M, met );
            }
        } else if( m_event_gen.getBaseSequence() != 0 ) {
            // use second strand
            res = copy_sequence( s, second, M );
        } else {
            res = copy_sequence( s, first, N );
        }

        return res;
    }

    virtual ~crossover_method() {}

protected:

/**
 *
 * Copies global sequence data to local stack buffers
 * Operates on stack buffers writing back to stack
 * Copies stack to final output vector
 *
 * Is read and write buffering beneficial?
 *
 * @return soft max of result sequence
 */
    template < class Method >
    unsigned int buffered_build_sequence( sequence_iterator res, sequence_iterator first, const unsigned int soft_N, sequence_iterator second, const unsigned int soft_M, const Method & m ) {
        const unsigned int N = 16;
        block_type first_buffer[ N ];   // 16 * 8 == 128 byte buffer
        block_type second_buffer[ N ];

        const unsigned int soft_max = (( soft_N > soft_M )? soft_N : soft_M );   // soft maximum length
        unsigned int last_block = 0;

        unsigned int l = 0;
        while( l < soft_max ) {
            unsigned int j = (soft_max - l);
            j = ((j > N) ? N : j);

            // read global data to local buffers
            memcpy( first_buffer, first + l, j * sizeof( block_type ) );
            memcpy( second_buffer, second + l, j * sizeof( block_type ) );

            unsigned int i = 0;
            while( i < j ) {
                const unsigned int offset = l + i;
                block_type first = ((offset < soft_N ) ? first_buffer[ i ] : bit_helper_type::ALL_UNSET);
                block_type second = ((offset < soft_M ) ? second_buffer[ i ] : bit_helper_type::ALL_UNSET);

                block_type mask = buffered_build_mask( first, second, offset * bit_helper_type::BITS_PER_BLOCK );

                mask = m( first, second, mask );
                second_buffer[ i ] = mask;
                ++i;
                if( mask ) {
                    last_block = offset + 1;
                }
            }

            // write to result sequence
            memcpy( res + l, second_buffer, j * sizeof(block_type) );
            l += j;
        }

        return last_block;
    }

/**
 * Unraveled the set bit decoding
 */
    block_type buffered_build_mask( block_type first, block_type second, unsigned int offset ) {
        block_type hets = first ^ second;
        block_type mask  = bit_helper_type::ALL_UNSET;   // mask state from second strand

        unsigned int het_buffer[ bit_helper_type::BITS_PER_BLOCK ]; // i.e. buffer_size = 64 * 4 = 256 bytes buffer

        if( hets ) {

            // decode set indices
            unsigned int j = 0;
            do {
                het_buffer[ j ] = bit_walker_type::unset_next_index( hets );
                ++j;
            } while( hets );

            // evaluate positions at relative indices
            unsigned int i = 0;
            while( i < j ) {
                unsigned int idx = het_buffer[ i ];
                if( m_event_gen( offset + idx ) ) {
                    mask |= clotho::utility::bit_masks[ idx ];
                }
                ++i;
            }
        }

        return mask;
    }

/**
 *
 * Initial technique for building a crossover mask
 *
 *
 */
    block_type build_mask( block_type first, block_type second, unsigned int offset ) {
        block_type hets = first ^ second;
        block_type mask = bit_helper_type::ALL_UNSET;   // mask state from second strand

        if( hets ) {
            do {
                unsigned int idx = bit_walker_type::unset_next_index( hets );

                if( m_event_gen( offset + idx ) ) {
                    mask |= clotho::utility::bit_masks[ idx ];
                }
            } while( hets );
        }

        return mask;
    }

    template < class Method >
    void build_sequence( sequence_iterator s, genome_iterator start, genome_iterator end, const Method & m ) {
        size_t j = 0;
        genome_iterator sec_ptr = end;
        while( start != end ) {
            block_type first = *start++;
            block_type second = *sec_ptr++;

            block_type mask = build_mask( first, second, j );

            *s++ = m(first, second, mask);

            j += bit_helper_type::BITS_PER_BLOCK;
        }
    }

/**
 *
 * Uses soft max of both sequence
 *
 * Is write buffer beneficial?
 *
 * @return soft max of result sequence
 */
    template < class Method >
    unsigned int buffered_write_build_sequence( sequence_iterator res, sequence_iterator first, const unsigned int soft_N, sequence_iterator second, const unsigned int soft_M, const Method & m ) {

        const unsigned int N = 32;
        block_type  _buffer[ N ];   // 256 byte buffer

        const unsigned int soft_max = (( soft_N > soft_M )? soft_N : soft_M );   // soft maximum length
        unsigned int last_block = 0;

        unsigned int i = 0, j = 0;

        while( j < soft_max ) {
            block_type a = ((j < soft_N ) ? first[ j ] : bit_helper_type::ALL_UNSET);
            block_type b = ((j < soft_M ) ? second[ j ] : bit_helper_type::ALL_UNSET);

            block_type mask = build_mask( a, b, j * bit_helper_type::BITS_PER_BLOCK );

            mask = m( a, b, mask );
            _buffer[ i++ ] = mask;
            ++j;

            if( mask ) {
                last_block = j;
            }

            if( i >= N ) {
                // buffer is full
                memcpy( res, _buffer, N * sizeof(block_type) );
                res += N;
                i = 0;
            }
        }

        // write final buffer
        if( i ) {
            memcpy( res, _buffer, i * sizeof( block_type ) );
        }

        return last_block;
    }

/**
 *
 *
 * @return soft max of result sequence
 */
    template < class Method >
    unsigned int build_sequence( sequence_iterator res, sequence_iterator first, const unsigned int N, sequence_iterator second, const unsigned int M, const Method & m ) {

        const unsigned int W = (( N > M )? N : M );
        unsigned int i = 0;
        unsigned int last_block = 0;
        while( i < W ) {
            block_type a = first[ i ];
            block_type b = second[ i ];

            block_type mask = build_mask( a, b, i * bit_helper_type::BITS_PER_BLOCK );

            mask = m(a, b, mask );
            res[ i ] = mask;
            ++i;

            if( mask ) {
                last_block = i;
            }
        }

        return last_block;
    }

    unsigned int copy_sequence( sequence_iterator s, sequence_iterator start, const size_t W ) {
        memcpy( s, start, W * sizeof(block_type));
        return W;
    }

    event_generator_type m_event_gen;
};

}   // namespace genetics
}   // namespace clotho

#endif  // CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
<|endoftext|>


<commit_before>//
//  StaticAnalyser.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 15/09/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "StaticAnalyser.hpp"

#include "../Disassembler/Disassembler6502.hpp"

using namespace StaticAnalyser::Atari;

static void DeterminePagingFor2kCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment)
{
	// if this is a 2kb cartridge then it's definitely either unpaged or a CommaVid
	uint16_t entry_address, break_address;

	entry_address = ((uint16_t)(segment.data[0x7fc] | (segment.data[0x7fd] << 8))) & 0x1fff;
	break_address = ((uint16_t)(segment.data[0x7fe] | (segment.data[0x7ff] << 8))) & 0x1fff;

	// a CommaVid start address needs to be outside of its RAM
	if(entry_address < 0x1800 || break_address < 0x1800) return;

	std::function<size_t(uint16_t address)> high_location_mapper = [](uint16_t address) {
		address &= 0x1fff;
		return (size_t)(address - 0x1800);
	};
	std::function<size_t(uint16_t address)> full_range_mapper = [](uint16_t address) {
		if(!(address & 0x1000)) return (size_t)-1;
		return (size_t)(address & 0x7ff);
	};

	StaticAnalyser::MOS6502::Disassembly high_location_disassembly =
		StaticAnalyser::MOS6502::Disassemble(segment.data, high_location_mapper, {entry_address, break_address});
//	StaticAnalyser::MOS6502::Disassembly full_range_disassembly =
//		StaticAnalyser::MOS6502::Disassemble(segment.data, full_range_mapper, {entry_address, break_address});

	// if there are no subroutines in the top 2kb of memory then this isn't a CommaVid
	bool has_appropriate_subroutine_calls = false;
	bool has_inappropriate_subroutine_calls = false;
	for(uint16_t address : high_location_disassembly.internal_calls)
	{
		const uint16_t masked_address = address & 0x1fff;
		has_appropriate_subroutine_calls |= (masked_address >= 0x1800);
		has_inappropriate_subroutine_calls |= (masked_address < 0x1800);
	}

	// assumption here: a CommaVid will never branch into RAM. Possibly unsafe: if it won't then what's the RAM for?
	if(!has_appropriate_subroutine_calls || has_inappropriate_subroutine_calls) return;

	std::set<uint16_t> all_writes = high_location_disassembly.external_stores;
	all_writes.insert(high_location_disassembly.external_modifies.begin(), high_location_disassembly.external_modifies.end());

	// a CommaVid will use its RAM
	if(all_writes.empty()) return;

	bool has_appropriate_accesses = false;
	for(uint16_t address : all_writes)
	{
		const uint16_t masked_address = address & 0x1fff;
		if(masked_address >= 0x1400 && masked_address < 0x1800)
		{
			has_appropriate_accesses = true;
			break;
		}
	}

	// in desperation, accept any kind of store that looks likely to be intended for large amounts of memory
	bool has_wide_area_store = false;
	if(!has_appropriate_accesses)
	{
		for(std::map<uint16_t, StaticAnalyser::MOS6502::Instruction>::value_type &entry : high_location_disassembly.instructions_by_address)
		{
			if(entry.second.operation == StaticAnalyser::MOS6502::Instruction::STA)
			{
				has_wide_area_store |= entry.second.addressing_mode == StaticAnalyser::MOS6502::Instruction::Indirect;
				has_wide_area_store |= entry.second.addressing_mode == StaticAnalyser::MOS6502::Instruction::IndexedIndirectX;
				has_wide_area_store |= entry.second.addressing_mode == StaticAnalyser::MOS6502::Instruction::IndirectIndexedY;
			}
		}
	}

	// conclude that this is a CommaVid if it attempted to write something to the CommaVid RAM locations;
	// caveat: false positives aren't likely to be problematic; a false positive is a 2KB ROM that always addresses
	// itself so as to land in ROM even if mapped as a CommaVid and this code is on the fence as to whether it
	// attempts to modify itself but it probably doesn't
	if(has_appropriate_accesses || has_wide_area_store)
		target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::CommaVid;
}

static void DeterminePagingFor8kCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const std::vector<StaticAnalyser::MOS6502::Disassembly> &disassemblies)
{
	std::set<uint16_t> internal_accesses;
	std::set<uint16_t> external_stores;
	for(const StaticAnalyser::MOS6502::Disassembly &disassembly : disassemblies)
	{
		internal_accesses.insert(disassembly.internal_stores.begin(), disassembly.internal_stores.end());
		internal_accesses.insert(disassembly.internal_modifies.begin(), disassembly.internal_modifies.end());
		internal_accesses.insert(disassembly.internal_loads.begin(), disassembly.internal_loads.end());
		external_stores.insert(disassembly.external_stores.begin(), disassembly.external_stores.end());
	}

	bool looks_like_atari = false;
	bool looks_like_parker_bros = false;
	for(uint16_t address : internal_accesses)
	{
		looks_like_atari |= ((address & 0x1fff) >= 0x1ff8) && ((address & 0x1fff) < 0x1ffa);
		looks_like_parker_bros |= ((address & 0x1fff) >= 0x1fe0) && ((address & 0x1fff) < 0x1fe8);
	}

	if(looks_like_parker_bros) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::ParkerBros;
	if(looks_like_atari) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::Atari8k;
}

static void DeterminePagingForCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment)
{
	if(segment.data.size() == 2048)
	{
		DeterminePagingFor2kCartridge(target, segment);
		return;
	}

	uint16_t entry_address, break_address;

	entry_address = (uint16_t)(segment.data[segment.data.size() - 4] | (segment.data[segment.data.size() - 3] << 8));
	break_address = (uint16_t)(segment.data[segment.data.size() - 2] | (segment.data[segment.data.size() - 1] << 8));

	std::function<size_t(uint16_t address)> address_mapper = [](uint16_t address) {
		if(!(address & 0x1000)) return (size_t)-1;
		return (size_t)(address & 0xfff);
	};

	std::vector<StaticAnalyser::MOS6502::Disassembly> disassemblies;
	std::set<uint16_t> internal_stores;
	std::set<uint16_t> external_stores;
	for(std::vector<uint8_t>::difference_type base = 0; base < segment.data.size(); base += 4096)
	{
		std::vector<uint8_t> sub_data(segment.data.begin() + base, segment.data.begin() + base + 4096);
		disassemblies.push_back(StaticAnalyser::MOS6502::Disassemble(sub_data, address_mapper, {entry_address, break_address}));
		internal_stores.insert(disassemblies.back().internal_stores.begin(), disassemblies.back().internal_stores.end());
		external_stores.insert(disassemblies.back().external_stores.begin(), disassemblies.back().external_stores.end());
	}

	if(segment.data.size() == 8192)
	{
		DeterminePagingFor8kCartridge(target, segment, disassemblies);
	}

	// check for any sort of on-cartridge RAM; that might imply a Super Chip or else immediately tip the
	// hat that this is a CBS RAM+ cartridge. Atari ROM images always have the same value stored over RAM
	// regions.
	bool has_superchip = true;
	bool is_ram_plus = true;
	for(size_t address = 0; address < 256; address++)
	{
		if(segment.data[address] != segment.data[0])
		{
			if(address < 128) has_superchip = false;
			is_ram_plus = false;
		}
	}
	target.atari.uses_superchip = has_superchip;
	if(is_ram_plus) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::CBSRamPlus;

	// check for a Tigervision or Tigervision-esque scheme
	if(target.atari.paging_model == StaticAnalyser::Atari2600PagingModel::None)
	{
		bool looks_like_tigervision = external_stores.find(0x3f) != external_stores.end();
		if(looks_like_tigervision) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::Tigervision;
	}
}

void StaticAnalyser::Atari::AddTargets(
	const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
	const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
	const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
	std::list<StaticAnalyser::Target> &destination)
{
	// TODO: any sort of sanity checking at all; at the minute just trust the file type
	// approximation already performed.
	Target target;
	target.machine = Target::Atari2600;
	target.probability = 1.0;
	target.disks = disks;
	target.tapes = tapes;
	target.cartridges = cartridges;
	target.atari.paging_model = Atari2600PagingModel::None;
	target.atari.uses_superchip = false;

	// try to figure out the paging scheme
	if(!cartridges.empty())
	{
		const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridges.front()->get_segments();

		if(segments.size() == 1)
		{
			const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
			DeterminePagingForCartridge(target, segment);
		}
	}

	destination.push_back(target);
}
<commit_msg>Added an earlier exit.<commit_after>//
//  StaticAnalyser.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 15/09/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "StaticAnalyser.hpp"

#include "../Disassembler/Disassembler6502.hpp"

using namespace StaticAnalyser::Atari;

static void DeterminePagingFor2kCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment)
{
	// if this is a 2kb cartridge then it's definitely either unpaged or a CommaVid
	uint16_t entry_address, break_address;

	entry_address = ((uint16_t)(segment.data[0x7fc] | (segment.data[0x7fd] << 8))) & 0x1fff;
	break_address = ((uint16_t)(segment.data[0x7fe] | (segment.data[0x7ff] << 8))) & 0x1fff;

	// a CommaVid start address needs to be outside of its RAM
	if(entry_address < 0x1800 || break_address < 0x1800) return;

	std::function<size_t(uint16_t address)> high_location_mapper = [](uint16_t address) {
		address &= 0x1fff;
		return (size_t)(address - 0x1800);
	};
	std::function<size_t(uint16_t address)> full_range_mapper = [](uint16_t address) {
		if(!(address & 0x1000)) return (size_t)-1;
		return (size_t)(address & 0x7ff);
	};

	StaticAnalyser::MOS6502::Disassembly high_location_disassembly =
		StaticAnalyser::MOS6502::Disassemble(segment.data, high_location_mapper, {entry_address, break_address});
//	StaticAnalyser::MOS6502::Disassembly full_range_disassembly =
//		StaticAnalyser::MOS6502::Disassemble(segment.data, full_range_mapper, {entry_address, break_address});

	// if there are no subroutines in the top 2kb of memory then this isn't a CommaVid
	bool has_appropriate_subroutine_calls = false;
	bool has_inappropriate_subroutine_calls = false;
	for(uint16_t address : high_location_disassembly.internal_calls)
	{
		const uint16_t masked_address = address & 0x1fff;
		has_appropriate_subroutine_calls |= (masked_address >= 0x1800);
		has_inappropriate_subroutine_calls |= (masked_address < 0x1800);
	}

	// assumption here: a CommaVid will never branch into RAM. Possibly unsafe: if it won't then what's the RAM for?
	if(!has_appropriate_subroutine_calls || has_inappropriate_subroutine_calls) return;

	std::set<uint16_t> all_writes = high_location_disassembly.external_stores;
	all_writes.insert(high_location_disassembly.external_modifies.begin(), high_location_disassembly.external_modifies.end());

	// a CommaVid will use its RAM
	if(all_writes.empty()) return;

	bool has_appropriate_accesses = false;
	for(uint16_t address : all_writes)
	{
		const uint16_t masked_address = address & 0x1fff;
		if(masked_address >= 0x1400 && masked_address < 0x1800)
		{
			has_appropriate_accesses = true;
			break;
		}
	}

	// in desperation, accept any kind of store that looks likely to be intended for large amounts of memory
	bool has_wide_area_store = false;
	if(!has_appropriate_accesses)
	{
		for(std::map<uint16_t, StaticAnalyser::MOS6502::Instruction>::value_type &entry : high_location_disassembly.instructions_by_address)
		{
			if(entry.second.operation == StaticAnalyser::MOS6502::Instruction::STA)
			{
				has_wide_area_store |= entry.second.addressing_mode == StaticAnalyser::MOS6502::Instruction::Indirect;
				has_wide_area_store |= entry.second.addressing_mode == StaticAnalyser::MOS6502::Instruction::IndexedIndirectX;
				has_wide_area_store |= entry.second.addressing_mode == StaticAnalyser::MOS6502::Instruction::IndirectIndexedY;
			}
		}
	}

	// conclude that this is a CommaVid if it attempted to write something to the CommaVid RAM locations;
	// caveat: false positives aren't likely to be problematic; a false positive is a 2KB ROM that always addresses
	// itself so as to land in ROM even if mapped as a CommaVid and this code is on the fence as to whether it
	// attempts to modify itself but it probably doesn't
	if(has_appropriate_accesses || has_wide_area_store)
		target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::CommaVid;
}

static void DeterminePagingFor8kCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const std::vector<StaticAnalyser::MOS6502::Disassembly> &disassemblies)
{
	std::set<uint16_t> internal_accesses;
	std::set<uint16_t> external_stores;
	for(const StaticAnalyser::MOS6502::Disassembly &disassembly : disassemblies)
	{
		internal_accesses.insert(disassembly.internal_stores.begin(), disassembly.internal_stores.end());
		internal_accesses.insert(disassembly.internal_modifies.begin(), disassembly.internal_modifies.end());
		internal_accesses.insert(disassembly.internal_loads.begin(), disassembly.internal_loads.end());
		external_stores.insert(disassembly.external_stores.begin(), disassembly.external_stores.end());
	}

	bool looks_like_atari = false;
	bool looks_like_parker_bros = false;
	for(uint16_t address : internal_accesses)
	{
		looks_like_atari |= ((address & 0x1fff) >= 0x1ff8) && ((address & 0x1fff) < 0x1ffa);
		looks_like_parker_bros |= ((address & 0x1fff) >= 0x1fe0) && ((address & 0x1fff) < 0x1fe8);
	}

	if(looks_like_parker_bros) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::ParkerBros;
	if(looks_like_atari) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::Atari8k;
}

static void DeterminePagingForCartridge(StaticAnalyser::Target &target, const Storage::Cartridge::Cartridge::Segment &segment)
{
	if(segment.data.size() == 2048)
	{
		DeterminePagingFor2kCartridge(target, segment);
		return;
	}

	uint16_t entry_address, break_address;

	entry_address = (uint16_t)(segment.data[segment.data.size() - 4] | (segment.data[segment.data.size() - 3] << 8));
	break_address = (uint16_t)(segment.data[segment.data.size() - 2] | (segment.data[segment.data.size() - 1] << 8));

	std::function<size_t(uint16_t address)> address_mapper = [](uint16_t address) {
		if(!(address & 0x1000)) return (size_t)-1;
		return (size_t)(address & 0xfff);
	};

	std::vector<StaticAnalyser::MOS6502::Disassembly> disassemblies;
	std::set<uint16_t> internal_stores;
	std::set<uint16_t> external_stores;
	for(std::vector<uint8_t>::difference_type base = 0; base < segment.data.size(); base += 4096)
	{
		std::vector<uint8_t> sub_data(segment.data.begin() + base, segment.data.begin() + base + 4096);
		disassemblies.push_back(StaticAnalyser::MOS6502::Disassemble(sub_data, address_mapper, {entry_address, break_address}));
		internal_stores.insert(disassemblies.back().internal_stores.begin(), disassemblies.back().internal_stores.end());
		external_stores.insert(disassemblies.back().external_stores.begin(), disassemblies.back().external_stores.end());
	}

	if(segment.data.size() == 8192)
	{
		DeterminePagingFor8kCartridge(target, segment, disassemblies);
	}

	// check for any sort of on-cartridge RAM; that might imply a Super Chip or else immediately tip the
	// hat that this is a CBS RAM+ cartridge. Atari ROM images always have the same value stored over RAM
	// regions.
	bool has_superchip = true;
	bool is_ram_plus = true;
	for(size_t address = 0; address < 256; address++)
	{
		if(segment.data[address] != segment.data[0])
		{
			if(address < 128) has_superchip = false;
			is_ram_plus = false;
			if(!has_superchip && !is_ram_plus) break;
		}
	}
	target.atari.uses_superchip = has_superchip;
	if(is_ram_plus) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::CBSRamPlus;

	// check for a Tigervision or Tigervision-esque scheme
	if(target.atari.paging_model == StaticAnalyser::Atari2600PagingModel::None)
	{
		bool looks_like_tigervision = external_stores.find(0x3f) != external_stores.end();
		if(looks_like_tigervision) target.atari.paging_model = StaticAnalyser::Atari2600PagingModel::Tigervision;
	}
}

void StaticAnalyser::Atari::AddTargets(
	const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
	const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
	const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
	std::list<StaticAnalyser::Target> &destination)
{
	// TODO: any sort of sanity checking at all; at the minute just trust the file type
	// approximation already performed.
	Target target;
	target.machine = Target::Atari2600;
	target.probability = 1.0;
	target.disks = disks;
	target.tapes = tapes;
	target.cartridges = cartridges;
	target.atari.paging_model = Atari2600PagingModel::None;
	target.atari.uses_superchip = false;

	// try to figure out the paging scheme
	if(!cartridges.empty())
	{
		const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridges.front()->get_segments();

		if(segments.size() == 1)
		{
			const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
			DeterminePagingForCartridge(target, segment);
		}
	}

	destination.push_back(target);
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "browser/ui/accelerator_util.h"

#include <stdio.h>

#include <string>

#include "base/string_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "ui/base/accelerators/accelerator.h"

namespace accelerator_util {

namespace {

// The sscanf is deprecated in Windows.
#if defined(OS_WIN)
#define SSCANF sscanf_s
#else
#define SSCANF sscanf
#endif

// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
  *shifted = false;
  switch (c) {
    case 8: case 0x7F: return ui::VKEY_BACK;
    case 9: return ui::VKEY_TAB;
    case 0xD: case 3: return ui::VKEY_RETURN;
    case 0x1B: return ui::VKEY_ESCAPE;
    case ' ': return ui::VKEY_SPACE;

    case 'a': return ui::VKEY_A;
    case 'b': return ui::VKEY_B;
    case 'c': return ui::VKEY_C;
    case 'd': return ui::VKEY_D;
    case 'e': return ui::VKEY_E;
    case 'f': return ui::VKEY_F;
    case 'g': return ui::VKEY_G;
    case 'h': return ui::VKEY_H;
    case 'i': return ui::VKEY_I;
    case 'j': return ui::VKEY_J;
    case 'k': return ui::VKEY_K;
    case 'l': return ui::VKEY_L;
    case 'm': return ui::VKEY_M;
    case 'n': return ui::VKEY_N;
    case 'o': return ui::VKEY_O;
    case 'p': return ui::VKEY_P;
    case 'q': return ui::VKEY_Q;
    case 'r': return ui::VKEY_R;
    case 's': return ui::VKEY_S;
    case 't': return ui::VKEY_T;
    case 'u': return ui::VKEY_U;
    case 'v': return ui::VKEY_V;
    case 'w': return ui::VKEY_W;
    case 'x': return ui::VKEY_X;
    case 'y': return ui::VKEY_Y;
    case 'z': return ui::VKEY_Z;

    case ')': *shifted = true; case '0': return ui::VKEY_0;
    case '!': *shifted = true; case '1': return ui::VKEY_1;
    case '@': *shifted = true; case '2': return ui::VKEY_2;
    case '#': *shifted = true; case '3': return ui::VKEY_3;
    case '$': *shifted = true; case '4': return ui::VKEY_4;
    case '%': *shifted = true; case '5': return ui::VKEY_5;
    case '^': *shifted = true; case '6': return ui::VKEY_6;
    case '&': *shifted = true; case '7': return ui::VKEY_7;
    case '*': *shifted = true; case '8': return ui::VKEY_8;
    case '(': *shifted = true; case '9': return ui::VKEY_9;

    case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
    case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
    case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
    case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
    case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
    case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
    case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
    case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
    case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
    case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
    case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;

    default: return ui::VKEY_UNKNOWN;
  }
}

}  // namespace

bool StringToAccelerator(const std::string& description,
                         ui::Accelerator* accelerator) {
  if (!IsStringASCII(description)) {
    LOG(ERROR) << "The accelerator string can only contain ASCII characters";
    return false;
  }
  std::string shortcut(StringToLowerASCII(description));

  std::vector<std::string> tokens;
  base::SplitString(shortcut, '+', &tokens);
  if (tokens.size() < 2 || tokens.size() > 4) {
    LOG(WARNING) << "Invalid accelerator description: " << description;
    return false;
  }

  // Now, parse it into an accelerator.
  int modifiers = ui::EF_NONE;
  ui::KeyboardCode key = ui::VKEY_UNKNOWN;
  for (size_t i = 0; i < tokens.size(); i++) {
    // We use straight comparing instead of map because the accelerator tends
    // to be correct and usually only uses few special tokens.
    if (tokens[i].size() == 1) {
      bool shifted = false;
      key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
      if (shifted)
        modifiers |= ui::EF_SHIFT_DOWN;
    } else if (tokens[i] == "ctrl") {
      modifiers |= ui::EF_CONTROL_DOWN;
    } else if (tokens[i] == "command") {
      // The "Command" would be translated to "Ctrl" on platforms other than
      // OS X.
#if defined(OS_MACOSX)
      modifiers |= ui::EF_COMMAND_DOWN;
#else
      modifiers |= ui::EF_CONTROL_DOWN;
#endif
    } else if (tokens[i] == "alt") {
      modifiers |= ui::EF_ALT_DOWN;
    } else if (tokens[i] == "shift") {
      modifiers |= ui::EF_SHIFT_DOWN;
    } else if (tokens[i] == "tab") {
      key = ui::VKEY_TAB;
    } else if (tokens[i] == "space") {
      key = ui::VKEY_SPACE;
    } else if (tokens[i] == "backspace") {
      key = ui::VKEY_BACK;
    } else if (tokens[i] == "delete") {
      key = ui::VKEY_DELETE;
    } else if (tokens[i] == "enter" || tokens[i] == "return") {
      key = ui::VKEY_RETURN;
    } else if (tokens[i] == "up") {
      key = ui::VKEY_UP;
    } else if (tokens[i] == "down") {
      key = ui::VKEY_DOWN;
    } else if (tokens[i] == "left") {
      key = ui::VKEY_LEFT;
    } else if (tokens[i] == "right") {
      key = ui::VKEY_RIGHT;
    } else if (tokens[i] == "home") {
      key = ui::VKEY_HOME;
    } else if (tokens[i] == "end") {
      key = ui::VKEY_END;
    } else if (tokens[i] == "pagedown") {
      key = ui::VKEY_PRIOR;
    } else if (tokens[i] == "pageup") {
      key = ui::VKEY_NEXT;
    } else if (tokens[i] == "esc") {
      key = ui::VKEY_ESCAPE;
    } else if (tokens[i] == "volumemute") {
      key = ui::VKEY_VOLUME_MUTE;
    } else if (tokens[i] == "volumeup") {
      key = ui::VKEY_VOLUME_UP;
    } else if (tokens[i] == "volumedown") {
      key = ui::VKEY_VOLUME_DOWN;
    } else if (tokens[i] == "medianexttrack") {
      key = ui::VKEY_MEDIA_NEXT_TRACK;
    } else if (tokens[i] == "mediaprevioustrack") {
      key = ui::VKEY_MEDIA_PREV_TRACK;
    } else if (tokens[i] == "mediastop") {
      key = ui::VKEY_MEDIA_STOP;
    } else if (tokens[i] == "mediaplaypause") {
      key = ui::VKEY_MEDIA_PLAY_PAUSE;
    } else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
      // F1 - F24.
      int n;
      if (SSCANF(tokens[i].c_str(), "f%d", &n) == 1 && n > 0 && n < 25) {
        key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
      } else {
        LOG(WARNING) << tokens[i] << "is not available on keyboard";
        return false;
      }
    } else {
      LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
      return false;
    }
  }

  if (key == ui::VKEY_UNKNOWN) {
    LOG(WARNING) << "The accelerator doesn't contain a valid key";
    return false;
  }

  *accelerator = ui::Accelerator(key, modifiers);
  SetPlatformAccelerator(accelerator);
  return true;
}

}  // namespace accelerator_util
<commit_msg>Do not use sscanf.<commit_after>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "browser/ui/accelerator_util.h"

#include <stdio.h>

#include <string>

#include "base/string_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "ui/base/accelerators/accelerator.h"

namespace accelerator_util {

namespace {

// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
  *shifted = false;
  switch (c) {
    case 8: case 0x7F: return ui::VKEY_BACK;
    case 9: return ui::VKEY_TAB;
    case 0xD: case 3: return ui::VKEY_RETURN;
    case 0x1B: return ui::VKEY_ESCAPE;
    case ' ': return ui::VKEY_SPACE;

    case 'a': return ui::VKEY_A;
    case 'b': return ui::VKEY_B;
    case 'c': return ui::VKEY_C;
    case 'd': return ui::VKEY_D;
    case 'e': return ui::VKEY_E;
    case 'f': return ui::VKEY_F;
    case 'g': return ui::VKEY_G;
    case 'h': return ui::VKEY_H;
    case 'i': return ui::VKEY_I;
    case 'j': return ui::VKEY_J;
    case 'k': return ui::VKEY_K;
    case 'l': return ui::VKEY_L;
    case 'm': return ui::VKEY_M;
    case 'n': return ui::VKEY_N;
    case 'o': return ui::VKEY_O;
    case 'p': return ui::VKEY_P;
    case 'q': return ui::VKEY_Q;
    case 'r': return ui::VKEY_R;
    case 's': return ui::VKEY_S;
    case 't': return ui::VKEY_T;
    case 'u': return ui::VKEY_U;
    case 'v': return ui::VKEY_V;
    case 'w': return ui::VKEY_W;
    case 'x': return ui::VKEY_X;
    case 'y': return ui::VKEY_Y;
    case 'z': return ui::VKEY_Z;

    case ')': *shifted = true; case '0': return ui::VKEY_0;
    case '!': *shifted = true; case '1': return ui::VKEY_1;
    case '@': *shifted = true; case '2': return ui::VKEY_2;
    case '#': *shifted = true; case '3': return ui::VKEY_3;
    case '$': *shifted = true; case '4': return ui::VKEY_4;
    case '%': *shifted = true; case '5': return ui::VKEY_5;
    case '^': *shifted = true; case '6': return ui::VKEY_6;
    case '&': *shifted = true; case '7': return ui::VKEY_7;
    case '*': *shifted = true; case '8': return ui::VKEY_8;
    case '(': *shifted = true; case '9': return ui::VKEY_9;

    case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
    case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
    case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
    case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
    case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
    case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
    case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
    case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
    case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
    case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
    case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;

    default: return ui::VKEY_UNKNOWN;
  }
}

}  // namespace

bool StringToAccelerator(const std::string& description,
                         ui::Accelerator* accelerator) {
  if (!IsStringASCII(description)) {
    LOG(ERROR) << "The accelerator string can only contain ASCII characters";
    return false;
  }
  std::string shortcut(StringToLowerASCII(description));

  std::vector<std::string> tokens;
  base::SplitString(shortcut, '+', &tokens);
  if (tokens.size() < 2 || tokens.size() > 4) {
    LOG(WARNING) << "Invalid accelerator description: " << description;
    return false;
  }

  // Now, parse it into an accelerator.
  int modifiers = ui::EF_NONE;
  ui::KeyboardCode key = ui::VKEY_UNKNOWN;
  for (size_t i = 0; i < tokens.size(); i++) {
    // We use straight comparing instead of map because the accelerator tends
    // to be correct and usually only uses few special tokens.
    if (tokens[i].size() == 1) {
      bool shifted = false;
      key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
      if (shifted)
        modifiers |= ui::EF_SHIFT_DOWN;
    } else if (tokens[i] == "ctrl") {
      modifiers |= ui::EF_CONTROL_DOWN;
    } else if (tokens[i] == "command") {
      // The "Command" would be translated to "Ctrl" on platforms other than
      // OS X.
#if defined(OS_MACOSX)
      modifiers |= ui::EF_COMMAND_DOWN;
#else
      modifiers |= ui::EF_CONTROL_DOWN;
#endif
    } else if (tokens[i] == "alt") {
      modifiers |= ui::EF_ALT_DOWN;
    } else if (tokens[i] == "shift") {
      modifiers |= ui::EF_SHIFT_DOWN;
    } else if (tokens[i] == "tab") {
      key = ui::VKEY_TAB;
    } else if (tokens[i] == "space") {
      key = ui::VKEY_SPACE;
    } else if (tokens[i] == "backspace") {
      key = ui::VKEY_BACK;
    } else if (tokens[i] == "delete") {
      key = ui::VKEY_DELETE;
    } else if (tokens[i] == "enter" || tokens[i] == "return") {
      key = ui::VKEY_RETURN;
    } else if (tokens[i] == "up") {
      key = ui::VKEY_UP;
    } else if (tokens[i] == "down") {
      key = ui::VKEY_DOWN;
    } else if (tokens[i] == "left") {
      key = ui::VKEY_LEFT;
    } else if (tokens[i] == "right") {
      key = ui::VKEY_RIGHT;
    } else if (tokens[i] == "home") {
      key = ui::VKEY_HOME;
    } else if (tokens[i] == "end") {
      key = ui::VKEY_END;
    } else if (tokens[i] == "pagedown") {
      key = ui::VKEY_PRIOR;
    } else if (tokens[i] == "pageup") {
      key = ui::VKEY_NEXT;
    } else if (tokens[i] == "esc") {
      key = ui::VKEY_ESCAPE;
    } else if (tokens[i] == "volumemute") {
      key = ui::VKEY_VOLUME_MUTE;
    } else if (tokens[i] == "volumeup") {
      key = ui::VKEY_VOLUME_UP;
    } else if (tokens[i] == "volumedown") {
      key = ui::VKEY_VOLUME_DOWN;
    } else if (tokens[i] == "medianexttrack") {
      key = ui::VKEY_MEDIA_NEXT_TRACK;
    } else if (tokens[i] == "mediaprevioustrack") {
      key = ui::VKEY_MEDIA_PREV_TRACK;
    } else if (tokens[i] == "mediastop") {
      key = ui::VKEY_MEDIA_STOP;
    } else if (tokens[i] == "mediaplaypause") {
      key = ui::VKEY_MEDIA_PLAY_PAUSE;
    } else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
      // F1 - F24.
      int n;
      if (base::StringToInt(tokens[i].c_str() + 1, &n)) {
        key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
      } else {
        LOG(WARNING) << tokens[i] << "is not available on keyboard";
        return false;
      }
    } else {
      LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
      return false;
    }
  }

  if (key == ui::VKEY_UNKNOWN) {
    LOG(WARNING) << "The accelerator doesn't contain a valid key";
    return false;
  }

  *accelerator = ui::Accelerator(key, modifiers);
  SetPlatformAccelerator(accelerator);
  return true;
}

}  // namespace accelerator_util
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ViewShellHint.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: pjunck $ $Date: 2004-10-28 13:27:19 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_VIEW_SHELL_HINT_HXX
#define SD_VIEW_SHELL_HINT_HXX

#ifndef _SFXHINT_HXX //autogen
#include <svtools/hint.hxx>
#endif

namespace sd {

/** Local derivation of the SfxHint class that defines some hint ids that
    are used by the ViewShell class and its decendants.
*/
class ViewShellHint
    : public SfxHint
{
public:
    enum HintId {
        // Indicate that a page resize is about to begin.
        HINT_PAGE_RESIZE_START,
        // Indicate that a page resize has been completed.
        HINT_PAGE_RESIZE_END,
        // Indicate that an edit mode change is about to begin.
        HINT_CHANGE_EDIT_MODE_START,
        // Indicate that an edit mode change has been completed.
        HINT_CHANGE_EDIT_MODE_END
    };

    TYPEINFO();

    ViewShellHint (HintId nHintId);

    HintId GetHintId (void) const;

private:
    HintId meHintId;
};

} // end of namespace sd

#endif
<commit_msg>INTEGRATION: CWS impress37 (1.2.160); FILE MERGED 2005/03/04 14:55:54 af 1.2.160.1: #i43382# Added two new hint ids.<commit_after>/*************************************************************************
 *
 *  $RCSfile: ViewShellHint.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 13:57:57 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_VIEW_SHELL_HINT_HXX
#define SD_VIEW_SHELL_HINT_HXX

#ifndef _SFXHINT_HXX //autogen
#include <svtools/hint.hxx>
#endif

namespace sd {

/** Local derivation of the SfxHint class that defines some hint ids that
    are used by the ViewShell class and its decendants.
*/
class ViewShellHint
    : public SfxHint
{
public:
    enum HintId {
        // Indicate that a page resize is about to begin.
        HINT_PAGE_RESIZE_START,
        // Indicate that a page resize has been completed.
        HINT_PAGE_RESIZE_END,
        // Indicate that an edit mode change is about to begin.
        HINT_CHANGE_EDIT_MODE_START,
        // Indicate that an edit mode change has been completed.
        HINT_CHANGE_EDIT_MODE_END,

        HINT_COMPLEX_MODEL_CHANGE_START,
        HINT_COMPLEX_MODEL_CHANGE_END
    };

    TYPEINFO();

    ViewShellHint (HintId nHintId);

    HintId GetHintId (void) const;

private:
    HintId meHintId;
};

} // end of namespace sd

#endif
<|endoftext|>


<commit_before><commit_msg>We shouldn't use BIDI_DEFAULT_(RTL|LTR) if we know the directionality of the page, because we won't like the result if string is mixed bidi (it may mark string as RTL instead of LTR if it starts with strong RTL characters, even if the global direction is LTR).<commit_after><|endoftext|>