File:  [Isaki's NoNo m68k/m88k emulator] / nono / lib / object.h
Revision 1.1.1.17 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:56 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// 基本オブジェクト
//

#pragma once

#include "mystring.h"
#include "object_id.h"
#include <functional>
#include <vector>

class Logger;
class Monitor;
class TextScreen;

// オブジェクト ID
constexpr uint OBJ_BANKRAM(uint n)		{ return OBJ_BANKRAM0 + n; }
constexpr uint OBJ_DMAC_CH(uint n)		{ return OBJ_DMAC_CH0 + n; }
constexpr uint OBJ_ETHERNET(uint n)		{ return OBJ_ETHERNET0 + n; }
constexpr uint OBJ_FDD(uint n)			{ return OBJ_FDD0 + n; }
constexpr uint OBJ_GFPIC(uint n)		{ return OBJ_GFPIC0 + n; }
constexpr uint OBJ_HOSTCOM(uint n)		{ return OBJ_HOSTCOM0 + n; }
constexpr uint OBJ_HOSTNET(uint n)		{ return OBJ_HOSTNET0 + n; }
constexpr uint OBJ_M88200(uint n)		{ return OBJ_M88200_0 + n; }
constexpr uint OBJ_MPU_MEMDUMP(uint n)	{ return OBJ_MPU_MEMDUMP0 + n; }
constexpr uint OBJ_NEREID_BOARD(uint n)	{ return OBJ_NEREID_BOARD0 + n; }
constexpr uint OBJ_VIRTIO_BLOCK(uint n)	{ return OBJ_VIRTIO_BLOCK0 + n; }
constexpr uint OBJ_XP_MEMDUMP(uint n)	{ return OBJ_XP_MEMDUMP0 + n; }

// ログ表示に指定するラムダ式の便利マクロ。
// fmt 内では __func__ が使えないので代わりに lam_func を使うこと。
// lstr("%s value=%d", lam_func, value) のようになる。
// 他のキャプチャ指定子が必要になったらまた考える。
#define lstr(fmt...)	\
	[&, lam_func = __func__] { (void)lam_func; return string_format(fmt); }

// モニタコールバックを宣言するマクロ。
// 強制力はないけどヘッダで宣言するところで使うこと。
// コールバック関数の型が変わった時にコンパイルエラーで検出させるため。
#define DECLARE_MONITOR_SCREEN(name)	void name (Monitor *, TextScreen&)
#define DECLARE_MONITOR_BITMAP(name)	void name (Monitor *, BitmapRGBX&)

// 基本オブジェクト
class Object
{
 public:
	// 引数はオブジェクト ID。
	// ID と紐付けされたオブジェクト名は、ログ表示名で、ログに前置される。
	// またコンストラクタ指定の場合はエイリアスにも登録する。
	// これは表示名と指示名が同じことが多いための便宜措置。
	// 指示名に表示名を使いたくない場合は ClearAlias() してから
	// AddAlias() すること。
	explicit Object(uint objid_);

	virtual ~Object();

	// ID を返す
	uint GetId() const { return objid; }
	const char *GetIdStr() const;

	// ID を文字列で返す
	static const char *GetIdStr(uint target_id);

	// オブジェクト名(ログ表示名)を取得する
	const std::string& GetName() const { return objname; }

	// エイリアスリストを返す
	const std::vector<std::string>& GetAliases() const { return log_aliases; }

	// 指定の id を持つオブジェクトを返す。
	// 実体は gMainApp.GetObject() を呼んでいる。
	// 隣のデバイスを参照したい人が全員 mainapp.h を include しなくて済む
	// ようにするための便宜上のもの。
	static Object *GetObject(uint target_id);

	// 指定の id を持つオブジェクトを型 T* にして返す版。
	template <typename T>
	static T *GetObject(uint target_id) {
		auto dev = dynamic_cast<T *>(GetObject(target_id));
		assert(dev);
		return dev;
	}

 protected:
	// オブジェクト名を newname に設定(更新)する。
	// 通常、オブジェクト名はコンストラクタで指定するが、コンストラクタ時点
	// ではまだ名前が決まらないような場合にだけ使う。
	// こちらはエイリアスには関与しない。
	virtual void SetName(const std::string& newname) {
		objname = newname;
	}

	// エイリアスをクリアする。
	// エイリアスは初期値として、コンストラクタで設定したオブジェクト名が
	// 1つ入っているが、これを削除したい時に使う。
	void ClearAlias() {
		log_aliases.clear();
	}

	// エイリアスを追加する。
	void AddAlias(const std::string& alias) {
		log_aliases.emplace_back(alias);
	}

 private:
	uint objid {};

	// オブジェクト名。
	// こちらはログの先頭に追加される。
	std::string objname {};

	// エイリアスのリスト。
	// こちらはログ名を指定する時に使う。
	std::vector<std::string> log_aliases {};

	// オブジェクト ID からオブジェクト名(ログ名)変換テーブル
	static const std::vector<const char *> idname;

	// オブジェクト ID を文字列にしたもの
	static const std::vector<const char *> idtext;

 public:
	//
	// ログ
	//

	// ログレベルを設定する
	virtual void SetLogLevel(int loglevel_);

	// メッセージ出力
	// メッセージは仮想時刻も現在の PC も表示しない。Init() など VM 実行前や
	// 仮想マシン(特に仮想時刻、PC) に関係ないあたりはこちらを使用。

	// レベル指定なし、フォーマット版。(レベルを評価した後で使う)
	void putmsgn(const char *fmt, ...) const __printflike(2, 3);

	// レベル指定あり、フォーマット版。
#define putmsg(lv, fmt...)	do {	\
	if (__predict_false(loglevel >= (lv))) {	\
		putmsgn(fmt);	\
	}	\
} while (0)

	// レベル指定あり、ラムダ式版。
	void putmsgf(int lv, std::function<std::string()> msgf) const {
		if (__predict_false(loglevel >= lv)) {
			putmsgn("%s", msgf().c_str());
		}
	}

	// ログ出力
	// ログは仮想時刻と現在の PC も表示する。VM 実行中は基本的にこれで表示。

	// レベル指定なし、フォーマット版。(レベルを評価した後で使う)
	virtual void putlogn(const char *fmt, ...) const __printflike(2, 3);

	// レベル指定あり、フォーマット版。
#define putlog(lv, fmt...)	do {	\
	if (__predict_false(loglevel >= (lv))) {	\
		putlogn(fmt);	\
	}	\
} while (0)

	// レベル指定あり、ラムダ式版。
	void putlogf(int lv, std::function<std::string()> msgf) const {
		if (__predict_false(loglevel >= lv)) {
			putlogn("%s", msgf().c_str());
		}
	}

	// オブジェクト登録時に代入される
	Logger *logger {};

	// ログレベルの目安
	// 0: 未実装動作などのデバッグログではない情報
	// 1: 大雑把なデバッグログ
	// 2: 詳細なデバッグログ
	// 3: うるさいデバッグログ
	int loglevel {};

 protected:
	// ログ直接出力
	void WriteLog(const char *) const;
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.