C#版 バグベアード擬き エンジン部

昨日の続きでエンジン部をC#へ移植。まだ詰めが残ってるけど、これでほぼできあがり。

using System;
using System.Collections.Generic;
#if BUG_WITHOUT_LOCATION_INFO
#else
using System.Diagnostics;
#endif

public class bug_puppy
{

    // 省略


    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_message
    //

    public class bug_message
    {
#if BUG_WITHOUT_LOCATION_INFO
#else
        public string file;
        public int line;
#if BUG_FUNCTION_NAME
        public string function_name;
#endif
#endif
        public string message;

        public bug_message()
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = null;
            line = 0;
#if BUG_FUNCTION_NAME
            function_name = null;
#endif
#endif
        }
        public bug_message(string a_message)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = null;
            line = 0;
#if BUG_FUNCTION_NAME
            function_name = null;
#endif
#endif
            message = a_message;
        }
#if BUG_WITHOUT_LOCATION_INFO
#else
#if BUG_FUNCTION_NAME
        public bug_message(string a_file, int a_line, string a_function_name)
#else
        public bug_message(string a_file, int a_line)
#endif
        {
            file = a_file;
            line = a_line;
#if BUG_FUNCTION_NAME
            function_name = a_function_name;
#endif
            message = null;
        }
#if BUG_FUNCTION_NAME
        public bug_message(string a_file, int a_line, string a_function_name, string a_message)
#else
        public bug_message(string a_file, int a_line, string a_message)
#endif
        {
            file = a_file;
            line = a_line;
#if BUG_FUNCTION_NAME
            function_name = a_function_name;
#endif
            message = a_message;
        }
#endif
        public bug_message(bug_message a)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = a.file;
            line = a.line;
#if BUG_FUNCTION_NAME
            function_name = a.function_name;
#endif
#endif
            message = a.message;
        }
        public bug_message(bug_message a, string a_message)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = a.file;
            line = a.line;
#if BUG_FUNCTION_NAME
            function_name = a.function_name;
#endif
#endif
            message = a_message;
        }
            
#if BUG_WITHOUT_LOCATION_INFO
#else
        public string get_file()
        {
            if (string.IsNullOrEmpty(file))
            {
                return "<?unknown?>#?";
            }
            else
            {
                return file;
            }
        }
        public int get_line()
        {
            return line;
        }
#if BUG_FUNCTION_NAME
        string get_function_name()
        {
            if (string.IsNullOrEmpty(function_name))
            {
                return "unknown_function";
            }
            else
            {
                return function_name;
            }
        }
#endif
#endif
        public string get_message()
        {
            return message;
        }
#if BUG_WITHOUT_LOCATION_INFO
#else
        public string get_location()
        {
            if (string.IsNullOrEmpty(file))
            {
                return "<?unknown?>#?";
            }
            else
            {
#if BUG_FUNCTION_NAME
                return string.Format("<{0}>#{1}@{2}", file, line.ToString(), get_function_name().c_str());
#else
                return string.Format("<{0}>#{1}", file, line.ToString());
#endif
            }
        }
#endif

        public string get_message_ex()
        {
#if BUG_WITHOUT_LOCATION_INFO
            return message;
#else
            if (string.IsNullOrEmpty(message))
            {
                return get_location();
            }
            else
            {
                return message;
            }
#endif
        }

        public string get_full_message()
        {
#if BUG_WITHOUT_LOCATION_INFO
            return message;
#else
            if (string.IsNullOrEmpty(file))
            {
                return message;
            }
            else
            if (string.IsNullOrEmpty(message))
            {
                return get_location();
            }
            else
            {
                return string.Format("{0} {1}", message, get_location());
            }
#endif
        }

        public bug_message create(string a_message)
        {
            return new bug_message(this, a_message);
        }

        public bug_message assign(bug_message a)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = a.file;
            line = a.line;
#if BUG_FUNCTION_NAME
            function_name = a.function_name;
#endif
#endif
            message = a.message;
            return this;
        }
        
        public bool Equals (bug_message a)
        {
            return
#if BUG_WITHOUT_LOCATION_INFO
#else
                file == a.file &&
                line == a.line &&
#if BUG_FUNCTION_NAME
                function_name == a.function_name &&
#endif
#endif
                message == a.message;
        }
        public bool less_than(bug_message a)
        {
            return
#if BUG_WITHOUT_LOCATION_INFO
#else
                file.CompareTo(a.file) < 0 ||
                (
                    file == a.file &&
                    (
                        line < a.line ||
                        (
                            line == a.line &&
                            (
#if BUG_FUNCTION_NAME
                                function_name.CompareTo(a.function_name) < 0 ||
                                (
                                    function_name == a.function_name &&
                                    (
#endif
#endif
                                        message.CompareTo(a.message) < 0
#if BUG_WITHOUT_LOCATION_INFO
#else
#if BUG_FUNCTION_NAME
                                    )
                                )
#endif
                            )
                        )
                    )
                )
#endif
                ;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_profiler
    //
    
    public delegate void bug_writer(bug_message text, IEnumerable<string> tags);

    [ThreadStatic] public static bug_writer trace_writer = null;
    [ThreadStatic] public static string last_stamp = null;

    class bug_profiler :IDisposable
    {
        bug_writer profile_writer;
        public int level;
        int bug_scope_count;
        long bug_scope_begin_time;
        Stack<bug_profile_time_score> score_stack = new Stack<bug_profile_time_score>();
        Dictionary<bug_message, bug_profile_time_score_set> profile_db = new Dictionary<bug_message, bug_profile_time_score_set>();
        
        long overall_start_time;
        bug_profile_time_score overall_time_score = new bug_profile_time_score();

        public bug_profiler(bug_writer a_profile_writer)
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            begin_bug_time(a_current_tick);

            profile_writer = a_profile_writer;
            level = 0;
            bug_scope_count = 0;
            bug_scope_begin_time = 0;
            overall_start_time = a_current_tick;
            push_time_score(overall_time_score);

            end_bug_time();
        }
        public void Dispose()
        {
        }

        [ThreadStatic] public static bug_profiler instance = null;

        //public static bug_profiler get_instance()
        //{
        //    return instance;
        //}

        public void push_time_score(bug_profile_time_score a_time_score, long a_current_tick)
        {
            if (null != this)
            {
                if (0 < bug_scope_count)
                {
                    if (0 < score_stack.Count)
                    {
                        if (bug_scope_begin_time < a_current_tick)
                        {
                            score_stack.Peek().self_time_set.bug_time += a_current_tick -bug_scope_begin_time;
                            bug_scope_begin_time = a_current_tick;
                        }
                    }
                }
                score_stack.Push(a_time_score);
            }
        }
        public void push_time_score(bug_profile_time_score a_time_score)
        {
            push_time_score(a_time_score, bug_profile_time_type.get_current_tick());
        }
        public void add_time_score(bug_message a_message, string a_start_stamp, bug_profile_time_score a_time_score)
        {
            if (null != this)
            {
                if (0 < score_stack.Count)
                {
                    score_stack.Peek().sub_time_set.add(a_time_score.get_all_time_set());
                }
                profile_db[a_message].add_score(a_start_stamp, a_time_score);
            }
        }
        public void pop_time_score(long a_current_tick)
        {
            if (null != this)
            {
                if (0 < score_stack.Count)
                {
                    if (0 < bug_scope_count)
                    {
                        if (bug_scope_begin_time < a_current_tick)
                        {
                            score_stack.Peek().self_time_set.bug_time += a_current_tick - bug_scope_begin_time;
                            bug_scope_begin_time = a_current_tick;
                        }
                    }
                    score_stack.Pop();
                }
            }
        }
        public void pop_time_score()
        {
            pop_time_score(bug_profile_time_type.get_current_tick());
        }

        public void begin_bug_time(long a_current_tick)
        {
            if (null != this)
            {
                if (0 == bug_scope_count++)
                {
                    bug_scope_begin_time = a_current_tick;
                }
            }
        }
        public void end_bug_time()
        {
            if (null != this)
            {
                if (0 == --bug_scope_count)
                {
                    if (0 < score_stack.Count)
                    {
                        score_stack.Peek().self_time_set.bug_time += bug_profile_time_type.get_current_tick() -bug_scope_begin_time;
                    }
                }
            }
        }
        
        protected void overall_scope_end()
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();

            begin_bug_time(a_current_tick);
            pop_time_score();
            overall_time_score.self_time_set.whole_time = bug_profile_time_type.get_current_tick() -overall_start_time;
            var overall_message = new bug_message
            (
#if BUG_WITHOUT_LOCATION_INFO
#else
                "overall_scope_label", 0,
#if BUG_FUNCTION_NAME
                "overall_scope_label",
#endif
#endif
                "overall_scope_label"
            );
            add_time_score(overall_message, "overall_scope_label", overall_time_score);
            end_bug_time();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_bug_time_scope
    //

    class bug_bug_time_scope :IDisposable
    {
        bug_profiler profiler;
        public bug_bug_time_scope()
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            profiler = bug_profiler.instance;
            if (null != profiler)
            {
                profiler.begin_bug_time(a_current_tick);
            }
        }
        public bug_bug_time_scope(long a_current_tick)
        {
            profiler = bug_profiler.instance;
            if (null != profiler)
            {
                profiler.begin_bug_time(a_current_tick);
            }
        }
        public void Dispose()
        {
            if (null != profiler)
            {
                profiler.end_bug_time();
            }
        }
    };
    
    
    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_profile_scope
    //
    
    class bug_profile_scope :IDisposable
    {
        public bug_profiler profiler;
        public string start_stamp;
        public long start_time;
        public bug_profile_time_score time_score;
        public bug_message message;
        
        public bug_profile_scope(string a_message_value)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            var call_stack = new StackFrame(1, true);
#endif
            bug_message a_message = new bug_message
            (
#if BUG_WITHOUT_LOCATION_INFO
#else
                call_stack.GetFileName(),
                call_stack.GetFileLineNumber(),
#if BUG_FUNCTION_NAME
                call_stack.GetMethod().Name,
#endif
#endif
                a_message_value
            );
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick))
            {
                profiler = bug_profiler.instance;

                start_stamp = last_stamp;
                start_time = a_current_tick;
                time_score = new bug_profile_time_score();
                message = new bug_message(a_message);

                profiler.push_time_score(time_score, a_current_tick);
            }
        }
        public bug_profile_scope(bug_message a_message)
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick))
            {
                profiler = bug_profiler.instance;

                start_stamp = last_stamp;
                start_time = a_current_tick;
                time_score = new bug_profile_time_score();
                message = new bug_message(a_message);

                profiler.push_time_score(time_score, a_current_tick);
            }
        }
        public void Dispose()
        {
            long current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(current_tick))
            {
                if (null != profiler)
                {
                    profiler.pop_time_score(current_tick);
                }
                time_score.self_time_set.whole_time = current_tick -start_time -time_score.get_sub_time_set().get_whole_time().value;
                time_score.self_time_set.work_time = time_score.get_self_time_set().get_whole_time().value -time_score.get_self_time_set().get_bug_time().value;
                if (null != profiler)
                {
                    profiler.add_time_score(message, start_stamp, time_score);
                }
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  write
    //

    public static void write(bug_message text, IEnumerable<string> tags)
    {
        long a_current_tick = bug_profile_time_type.get_current_tick();
        using (var bug_time_scope = new bug_bug_time_scope(a_current_tick))
        {
            if (null != trace_writer)
            {
                trace_writer(text, tags);
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_scope
    //

    class bug_scope : bug_profile_scope, IDisposable
    {
        public IEnumerable<string> tags;

        public bug_scope(bug_message a_message, IEnumerable<string> a_tags)
            :base(a_message)
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick)
            {
                tags = a_tags;
                write(message.create(string.Format("▽{0}", message.get_message())), a_tags);
                if (null != profiler)
                {
                    ++profiler.level;
                }
            }
        }
        public new void Dispose()
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick)
            {
                write(message.create(string.Format("△{0}", message.get_message())), tags);
                if (null != profiler)
                {
                    --profiler.level;
                }
            }
            base.Dispose();
        }
    }

}