IFDEBUG 2: Как жить без фаталов?

Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
cJass
Тип:
Наработка
Думаю многие помнят небольшую, но очень полезную библиотечку от Doc которая помогала сохранять дебаг логи на хард по средствам прелоада и библиотечку от Скорпи, которая помогала контролировать в коде соблюдение различных условий.
Думаю, те кто пользовались, остались довольны, как и я.
Так вот, недавно Faion малость усовершенствовал первую, а скорпи присоединил вторую. Надеюсь, док и faion будут не против.
В результате получилось отличное средство от геморроя и немного от фаталов!

Инструкции

//     Instructions:
//
//     Пишет информацию об условии в лог, если условие ВЫПОЛНИЛОСЬ:
// IFDEBUG( ARGUMENT ) 
//
//     Пишет информацию в лог, если условие НЕ ВЫПОЛНЕНО и УНИЧТОЖАЕТ весь текущий поток:
// ASSERT( ARGUMENT ) 
//
//     Пишет информацию об условии в лог, если условие ВЫПОЛНИЛОСЬ и выходит из функции со значением, указанным во втором аргументе:
// IFDEBUG( ARGUMENT, RET )
//
// Заметка: Если функция ничего не возвращает, но вы в любом случае хотите её остановить, используйте пробел, как: IFDEBUG(u == null, );
// Заметка: Лог пишется только в режиме отладки JNGP - "Debug Mode".

Code

//     Instructions:
//
//     Writes log if the condition is satisfied:
// IFDEBUG( ARGUMENT ) 
//
//     Writes log if the condition is NOT satisfied and TERMINATES its thread:
// ASSERT( ARGUMENT ) 
//
//     Writes log if the condition is satisfied and returns value from the second argument:
// IFDEBUG( ARGUMENT, RET )
//
// Note: If the function returns nothing but you wanna stop it anyway, use the space like: IFDEBUG(u == null, );
// Note: Log is written only in JNGP "Debug Mode".

//     Configuration:
#define
{
    Debug = true
    private SavePath = NS_SNW_LOGS\\Logs
    private PerformanceSavePath = NS_SNW_LOGS\\PerformanceLogs
    private SaveOnHardDrive = true
    private HardDriveLetter = C
    private AutoSaveLog = true
    private LogSavePeriod = 5.0
}

// by Faion, 2012
// by DoctorGester (Doc), 2011

library DebugLog initializer DebugLogInit
{
    public bool EnableLogging = true
    private string array DebugLog
    private string array PerformanceDebugLog
    private int CurrentString = 0
    private int miliSeconds = 0
    private int Seconds = 0
    private int Minutes = 0
    private int Hours = 0
    private constant int StringLimit = 200
    
    private int pastVal = 0;
    private int PerformanceString = 0
    
    void PerformanceLogAdd()
    {
        if (!EnableLogging)
        {
            return
        }
        string min = I2S(Minutes)
        string sec = I2S(Seconds)
        string msec = I2S(miliSeconds)
        if (Minutes < 10)
        {
            min = "0" + min
        }
        if (Seconds < 10)
        {
            sec = "0" + sec
        }
        if (miliSeconds < 10)
        {
            msec = "0" + msec
        }
        location loc = Location(0,0);
        int hId = GetHandleId(loc);
        
        RemoveLocation(loc);
        loc = null;
        PerformanceDebugLog[PerformanceString] = PerformanceDebugLog[PerformanceString] + ("[" + I2S(Hours)+":" + min + ":" + sec + ":" + msec + "] " + I2S(hId-0x100000) + "\n")
        if (StringLength(PerformanceDebugLog[PerformanceString]) >= StringLimit)
        {
            PerformanceString++
        }
    }
    
    void PerformanceLogUpdate()
    {
        if (!EnableLogging)
        {
            return
        }
        PreloadGenClear()
        PreloadGenStart()
        int i = 0
        while (i <= PerformanceString)
        {
            Preload("\")\n" + PerformanceDebugLog[i] + "\n(\"")
            i++
        }
        #if SaveOnHardDrive
            PreloadGenEnd(`HardDriveLetter` + ":\\" + `PerformanceSavePath` + ".txt")
        #else
            PreloadGenEnd("\\" + `PerformanceSavePath` + ".txt")
        #endif
    }
    
    void LogAdd(string s)
    {
        if (!EnableLogging)
        {
            return
        }
        string min = I2S(Minutes)
        string sec = I2S(Seconds)
        string msec = I2S(miliSeconds)
        if (Minutes < 10)
        {
            min = "0" + min
        }
        if (Seconds < 10)
        {
            sec = "0" + sec
        }
        if (miliSeconds < 10)
        {
            msec = "0" + msec
        }
        DebugLog[CurrentString] = DebugLog[CurrentString] + ("[" + I2S(Hours)+":" + min + ":" + sec + ":" + msec + "] " + s + "\n")
        if (StringLength(DebugLog[CurrentString]) >= StringLimit)
        {
            CurrentString++
        }
    }
    
    void LogClear()
    {
        int i = 0
        while (i <= CurrentString)
        {
            DebugLog[i] = ""
            i++
        }
        CurrentString = 0
    }
    
    void LogUpdate()
    {
        if (!EnableLogging)
        {
            return
        }
        PreloadGenClear()
        PreloadGenStart()
        int i = 0
        while (i <= CurrentString)
        {
            Preload("\")\n" + DebugLog[i] + "\n(\"")
            i++
        }
        #if SaveOnHardDrive
            PreloadGenEnd(`HardDriveLetter` + ":\\" + `SavePath` + ".txt")
        #else
            PreloadGenEnd("\\" + `SavePath` + ".txt")
        #endif
    }
    
    private void DebugLogOnTimer()
    {
        miliSeconds++
        if (miliSeconds > 99)
        {
            miliSeconds = 0
            Seconds++
            if (Seconds > 59)
            {
                Seconds = 0
                Minutes++
                if (Minutes > 59)
                {
                    Minutes = 0
                    Hours++
                }
            }
        }
    }

    private void DebugLogInit()
    {
        #if AutoSaveLog
            TimerStart(CreateTimer(), LogSavePeriod, true, function LogUpdate)
            TimerStart(CreateTimer(), LogSavePeriod, true, function PerformanceLogUpdate)
        #endif
        TimerStart(CreateTimer(), 0.01, true, function DebugLogOnTimer)
        TimerStart(CreateTimer(), 0.10, true, function PerformanceLogAdd)
        LogAdd("By FaionBezarius. Last compilation: " + `DATE` + " " + `TIME`)
	#if Debug 
        	BJDebugMsg("By FaionBezarius. Last compilation: " + `DATE` + " " + `TIME`)
	#endif
    }
	
	
//   by ScorpioT1000, 2009
//   powered by AdicHelper(cJass.xgm.ru)

    #define private assert_color = "FF404040"

    nothing Ifdebug_debug_msg(string message, integer whichPlayer) {
    	LogAdd("|c"+assert_color+"Debug: "+message+"|r")
    }
    
    #define private DMSGFUNC = Ifdebug_debug_msg
    
	#define IFDEBUGF(ARG,DEST_PLAYER) =  
    #define IFDEBUGFA(ARG,DEST_PLAYER) = {
        if(ARG) {
        } else {
			I2R(2/0)
		}
    }
	    #define IFDEBUGR(ARG,WHATRET,DEST_PLAYER) = {
        if(ARG) {
            return WHATRET
        }
    }
	
#if DEBUG == 1
    #setdef IFDEBUGF(ARG,DEST_PLAYER) = {
        if(ARG) {
            DMSGFUNC(`FUNCNAME` + ": " + `ARG`,DEST_PLAYER)
        }
    }
    #setdef IFDEBUGFA(ARG,DEST_PLAYER) = {
        if(ARG) {
        } else {
		DMSGFUNC(`FUNCNAME` + ": " + `ARG` + " failed",DEST_PLAYER)
		I2R(2/0)
		}
    }
    
    #setdef IFDEBUGR(ARG,WHATRET,DEST_PLAYER) = {
        if(ARG) {
            DMSGFUNC(`FUNCNAME` + ": " + `ARG`,DEST_PLAYER)
            return WHATRET
        }
    }
#endif
    
    //overloading
    #define {
    ASSERT(ARGUMENT) = IFDEBUGFA(ARGUMENT, -1)
        IFDEBUG(ARGUMENT) = IFDEBUGF(ARGUMENT, -1) // with condition to all players
        IFDEBUG(ARGUMENT,RET) = IFDEBUGR(ARGUMENT,RET, -1) // with condition and return to all players
        IFDEBUGP(ARGUMENT,DEST_PLAYER) = IFDEBUGF(A,DEST_PLAYER) // with condition to one player
        IFDEBUGP(ARGUMENT,RET,DEST_PLAYER) = IFDEBUGF(A,RET,DEST_PLAYER) // with condition and return to one players
    }
    
}

Примеры

// функция остановится и в лог будет записано, что выполнено условие "u == null" в функции "foo"
function foo takes unit u returns nothing
    IFDEBUG(u == null, )
    KillUnit(u)
endfunction

// если не будет выполнено условие "x > 0", будет остановлена вся цепочка вызывавших ее функций и в логе будет запись об этой функции и условии
function xab takes integer a, integer b, integer c returns integer
    local integer x = a * b * c
    ASSERT(x > 0)
    return SquareRoot(x)
endfunction

// вернет false если хотябы один из юнитов равен null, запишет всё в лог
function bvc takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local unit t = GetSpellTargetUnit()
    IFDEBUG(u == 0 or t == null, false)
    // ...
    return true
endfunction
Вот для тех, кто хочет понять истинный смысл: это просто - ты вставляешь этот код ВЕЗДЕ, во всех функциях и т.п. Естественно, доводишь до того состояния, чтобы ни одной ошибки не выходило. И когда проводишь рефакторинг, т.е. меняешь что-то внутри, меняешь логику или просто добавляешь функционал, проводишь ручные тесты и видишь ошибки - их легко исправить, сразу ясно, где и что случилось.
Это полный выигрыш перед вашими if () then BJDebugMsg("АЛАЛАЛААЛМАМА").
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
29
12 лет назад
0
ScorpioT1000, опять неоправданные нано секунды?
0
37
12 лет назад
0
alexprey, ты не понимаешь что тут можно ее вставить в циклы например?
3
19
12 лет назад
3
ScorpioT1000:
alexprey, ты не понимаешь что тут можно ее вставить в циклы например?
И? Ты такой тупой ей богу, эти наносекунды погоды не сделают. вообще
5
29
12 лет назад
5
ScorpioT1000, не притворяйся идиотом.
1000 итераций цикла, и это затраты перейдут в микро. По сравнению со сравнением это настолько мало, что можно пренебречь этой фигней. И вообще если так трестись из-за наносекунд может тогда весь код писать на чистом jass с ручной оптимизацией и обусфикацией?
0
37
12 лет назад
Отредактирован ScorpioT1000
0
Дождливую погоду я могу сделать разве что у кого-то во рту.
И вообще если так трестись из-за наносекунд может тогда весь код писать на чистом jass с ручной оптимизацией и обусфикацией?
Зачем? В моей части кода всё и так идеально =)
Кстати в идеале на jass надо длину имен функций и переменных минимизировать, особенно массивы, вот почему обфускаторы всегда мастхев =)
Вот для тех кто хочет понять истинный смысл это просто - ты вставляешь этот код ВЕЗДЕ во всех функциях итп. Естественно доводишь до того состояния, чтобы ни одной ошибки не выходило. И когда проводишь рефакторинг, т.е. меняешь что-то внутри, меняешь логику или просто добавляешь функционал, проводишь ручные тесты и видишь ошибки - их легко исправить, сразу ясно, где и что случилось. Это полный выигрыш перед вашими if () then BJDebugMsg("АЛАЛАЛААЛМАМА").
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.
2
29
12 лет назад
2
при этом сделано как if () then DJDebugMsg <_<
0
37
12 лет назад
0
alexprey, ты знаешь понятие "внедрение" ? Так вот IFDEBUG предполагает постоянное, комплексное использование, а не временное.
Вот ты подсказал кстати. Можно при отключенном дебаге сделать те же проверки тока без вывода в лог.
done =)
2 комментария удалено
1
19
12 лет назад
1
ScorpioT1000:
alexprey, ты знаешь понятие "внедрение" ? Так вот IFDEBUG предполагает постоянное, комплексное использование, а не временное.
Вот ты подсказал кстати. Можно при отключенном дебаге сделать те же проверки тока без вывода в лог.
done =)
Чем тебе debug call мешает и его включение и отключение? Также комплексно включил, отключил одним нажатием. Ты просто не шаришь, и производишь говно на свет которое - не нужно.
2
29
12 лет назад
2
YellowStar, скорп шарящий, но иногда несет пургу
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.