Files
hakorune/src/finalization.rs

113 lines
3.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Nyash Finalization System - Memory Management
*
* fini()によるメモリ管理システムの実装
* - 解放済みBoxの追跡
* - スコープベースの自動解放
* - 再代入時の自動解放
*/
use crate::box_trait::NyashBox;
use crate::instance_v2::InstanceBox;
use lazy_static::lazy_static;
use std::collections::HashSet;
use std::fmt;
use std::sync::{Arc, Mutex};
lazy_static! {
/// グローバルな解放済みBox ID管理
static ref FINALIZED_BOXES: Arc<Mutex<HashSet<u64>>> = Arc::new(Mutex::new(HashSet::new()));
}
/// Boxが既に解放済みかチェック
pub fn is_finalized(box_id: u64) -> bool {
FINALIZED_BOXES.lock().unwrap().contains(&box_id)
}
/// Boxを解放済みとして記録
pub fn mark_as_finalized(box_id: u64) {
FINALIZED_BOXES.lock().unwrap().insert(box_id);
}
/// Box解放管理
pub struct BoxFinalizer {
/// このスコープで作成されたBox ID
created_boxes: Vec<(u64, Box<dyn NyashBox>)>,
/// finalization除外対象のBox ID関数の返り値など
excluded_boxes: HashSet<u64>,
}
impl BoxFinalizer {
pub fn new() -> Self {
Self {
created_boxes: Vec::new(),
excluded_boxes: HashSet::new(),
}
}
/// 新しいBoxを追跡対象に追加
pub fn track(&mut self, nyash_box: Box<dyn NyashBox>) {
let box_id = nyash_box.box_id();
self.created_boxes.push((box_id, nyash_box));
}
/// 指定したBoxを解放対象から除外関数の返り値など
pub fn exclude_from_finalization(&mut self, nyash_box: &Box<dyn NyashBox>) {
let box_id = nyash_box.box_id();
self.excluded_boxes.insert(box_id);
}
/// スコープ終了時に全てのBoxを解放除外対象を除く
pub fn finalize_all(&mut self) {
// 作成順(古い順)に解放
for (box_id, nyash_box) in &self.created_boxes {
// 除外対象は解放しない
if self.excluded_boxes.contains(box_id) {
continue;
}
if !is_finalized(*box_id) {
// fini()メソッドを呼び出す(存在する場合)
if let Some(instance) = nyash_box.as_any().downcast_ref::<InstanceBox>() {
let _ = instance.fini();
}
mark_as_finalized(*box_id);
}
}
self.created_boxes.clear();
self.excluded_boxes.clear();
}
}
impl Drop for BoxFinalizer {
fn drop(&mut self) {
self.finalize_all();
}
}
impl fmt::Debug for BoxFinalizer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BoxFinalizer")
.field("created_boxes_count", &self.created_boxes.len())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_finalization_tracking() {
let box_id = 12345;
assert!(!is_finalized(box_id));
mark_as_finalized(box_id);
assert!(is_finalized(box_id));
// 二重解放チェック
mark_as_finalized(box_id); // 問題なし
assert!(is_finalized(box_id));
}
}