Кресты / Говнокод #26628 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
template<typename CharType>
class Formatter
{
private:
	static int _ToString(Int32 Value){
		return CString<CharType>::Snprintf(
			(CharType*)GSupportToStringBuffer,
			TO_STRING_BUFFER_SIZE,
			"%" PRId32,
			Value);
	}
	static int _ToString(float Value){
		return CString<CharType>::Snprintf(
			(CharType*)GSupportToStringBuffer,
			TO_STRING_BUFFER_SIZE,
			"%f",
			Value);
	}
	template<typename First, typename ... Args>
	static void _ConvertArgs(Array<GenericString<CharType>>& _ArgBuffer, const First& _First, const Args& ... _Args)	{
		_ArgBuffer.Add(ToString(_First));
		_ConvertArgs(_ArgBuffer, _Args ...);
	}
	template<typename First>
	static void _ConvertArgs(Array<GenericString<CharType>>& _ArgBuffer, const First& _First)	{
		_ArgBuffer.Add(ToString(_First));
	}
	static bool _ScanPlaceholder(const CharType* Format, size_t Index, size_t Length, size_t& Placeholder, size_t& LastIndex)	{
		size_t i = Index;
		size_t j = 0;
		while (i < Length && Format[i] != FormatterPlaceholder<CharType>::End)
		{
			if (!Char<CharType>::IsDigit(Format[i]))
			{
				return false;
			}
			else
			{
				GSupportToStringBuffer[j] = Format[i];
				j++;
			}
			i++;
		}
		if (i == Length)
			return false;
		
		GSupportToStringBuffer[j] = 0;
#if defined(64BIT)
		Placeholder = CString<CharType>::Atoi64((const CharType*)GSupportToStringBuffer);
#else
		Placeholder = CString<CharType>::Atoi((const CharType*)GSupportToStringBuffer);
#endif
		LastIndex = i;
		return true;
	}
public:
	template<typename T>
	static GenericString<CharType> ToString(const T& Value)	{
		int Length = Formatter<CharType>::_ToString(Value);
		return GenericString<CharType>((char*)GSupportToStringBuffer, Length);
	}
	template<typename ... Args>
	static GenericString<CharType> Format(const CharType* Format, const Args& ... _Args)	{
		Array<GenericString<CharType>> _FormatedArgs;
		_FormatedArgs.Reserve(sizeof...(Args));
		Formatter<CharType>::_ConvertArgs(_FormatedArgs, _Args ...);
		
		const size_t _Length = CString<CharType>::Strlen(Format);
		size_t Index = 0;
		for (size_t i = 0; i < _Length; i++)
		{
			if (Format[i] == FormatterPlaceholder<CharType>::Begin)
			{
				size_t Placeholder = 0;
				size_t LastIndex = 0;
				if (_ScanPlaceholder(Format, i + 1, _Length, Placeholder, LastIndex) && Placeholder < sizeof...(Args))
				{
					Memory::Copy(GSupportFormatBuffer + Index,	_FormatedArgs[Placeholder].Data(),	_FormatedArgs[Placeholder].Length() * sizeof(CharType));
					Index += _FormatedArgs[Placeholder].Length();
					i = LastIndex;
				}
			}
			else
			{
				GSupportFormatBuffer[Index] = Format[i];
				Index++;
			}
		}
		GSupportFormatBuffer[Index] = 0;
		return GenericString<CharType>((const CharType*)GSupportFormatBuffer);
	}
};
template<typename T>
forceinline String ToString(const T& Value){
	return Formatter<char>::ToString<T>(Value);
}
template<typename ... Args>
forceinline String Format(const char* Format, const Args& ... _Args){
	return Formatter<char>::Format(Format, _Args ...);
}

Три года назад писал printf аля Console.WriteLine в C#. Тут порезал до ста строк. https://pastebin.com/8BCLuBEm

Запостил: Avery Avery, (Updated )

Комментарии (32) RSS

  • у меня было проще

    template <class Arg1>
        inline void log_req(Arg1 arg1)
        {
            if constexpr (std::is_enum_v<Arg1>)
            {
                std::cout << static_cast<int>(arg1);
            }
            else
            {
                std::cout << arg1;
            }
        }
    
        template <class Arg1, class... Args>
        inline void log_req(Arg1 arg1, Args... args)
        {
            std::cout << arg1;
            log_req(args...);
        }
    
        template <class... Args>
        void log(Args... args)
        {
            log_req(args...);
            std::cout << std::endl;
        }
    Ответить
    • Копирование аргументов на каждый вызов — не самое лучшее поведение.
      Ответить
      • там нет копирования аргументов - это все инлайн .... инлайн 🙂
        Ответить
          • Есть же какие-то нестандартные питушни, чтобы форсить инлайн.
            Ответить
            • Да, конпеляторозависимые, вроде «__forceinline» в «MSVC» и «__attribute__((always_inline))» в «gcc». Они, разумеется, в данном случае тоже не помогут, потому что при педераче аргументов по значению конпелятор обязан их педерать, внезапно, по значению — то есть скопировать.
              Ответить
              • А если речь не про кресты, а про няшную?

                Копирование говна у няшной вроде бы не имеет спецэффектов, так что можно скопировать , а можно заинлайнить. А у крестов же вроде не так
                Ответить
                • Надо Стандарт няшной читать, но на первый взгляд вроде нормально работает.
                  https://gcc.godbolt.org/z/f1vn2h — конпелятор настолько умный, что даже не выделяет память под структурку, а сразу передаёт в log() нужные значения. Какой багор )))
                  Ответить
                  • Интересно, что функицю он оставляет, хотя и не вызывает.

                    А вот если явно сказать вот так
                    void inline __attribute__((always_inline)) log_value_inline(int i)
                    {
                        printf("%s", i);
                    }
                    
                    int main()
                    {
                        log_value_inline(1);    
                        return 0;
                    }

                    то он и функцию выкидывеет.

                    Он даже вот так заинлайнил, и bar выкинул вообще
                    inline void  __attribute__((always_inline)) log_value_inline(int i)
                    {
                        printf("%d", i);
                    }
                    
                    void bar(void (*foo)(int)) {
                        (*foo)(1);
                    }
                    
                    int main()
                    {    
                        bar(&log_value_inline);    
                        return 0;
                    }



                    Давайте попробуем наебать мерзавца
                    inline void  __attribute__((always_inline)) log_value_inline(int i)
                    {
                        printf("%d", i);
                    }
                    
                    void bar(void (*foo)(int)) {
                        char a = getc(stdin);
                        if (a == 'q') {
                         (*foo)(1);
                        }
                    }
                    
                    int main()
                    {    
                        bar(&log_value_inline);    
                        return 0;
                    }


                    Да, против getc он не сдюжил
                    Ответить
          • inline вроде бы всегда было добрым советом, примерно как register, нет?
            Ответить
              • хм, а что будет, если я не поставлю inline? Вроде как линкер ебанется если только ты явно экспортнешь функции.. хотя неэеспоритруемые фукнции я бы все одно помечал static
                Ответить
                • > хм, а что будет, если я не поставлю inline?
                  ODR нарушица.
                  // test_1.h
                  #pragma once
                  
                  int sum(int a, int b)
                  {
                      return a + b;
                  }
                  
                  // test_1.cpp
                  #include <iostream>
                  #include "test_1.h"
                  
                  int main()
                  {
                      std::cout << sum(40, 2) << std::endl;
                  
                      return 0;
                  }
                  
                  // test_2.cpp
                  #include <iostream>
                  #include "test_1.h"
                  
                  void some_func(int a, int b)
                  {
                      std::cout << sum(a, b) << std::endl;
                  }
                  
                  // 1>test_2.obj : error LNK2005: "int __cdecl sum(int,int)" (?sum@@YAHHH@Z) already defined in test_1.obj
                  // fatal error LNK1169: one or more multiply defined symbols found


                  UPD: Джвух заголовочных файлов не надо, одного достаточно.
                  Ответить
                  • а) это если ты компилируешь все модули вместе?

                    мне казалось, что ODR не нарушается, если код один-в-один одинаковый везде, нет?

                    Но всё равно лучше просто помечать staticом то, что не хочшеь экспортить
                    Ответить
                    • Да.

                      > мне казалось, что ODR не нарушается, если код один-в-один одинаковый везде, нет?
                      Так будет с «inline» (причём если код будет не один-в-один, то возникнет что? Пра-а-авильно, UB!), а без него не сработает.
                      «static» поможет, но объявленные таким образом функции будут разными в каждом translation unit-е. А вот с «inline» они будут одними и теми же:

                      // test_1.h
                      #pragma once
                      
                      inline int sum(int a, int b)
                      {
                          static int call_count = 0;
                          call_count++;
                          std::cout << "Sum, call_count: " << call_count << std::endl;
                          return a + b;
                      }
                      
                      // test_1.cpp
                      #include <iostream>
                      #include "test_1.h"
                      
                      void some_func(int a, int b);
                      int main()
                      {
                          some_func(80, 4);
                          std::cout << sum(40, 2) << std::endl;
                      
                          return 0;
                      }
                      
                      // test_2.cpp
                      #include <iostream>
                      #include "test_1.h"
                      
                      void some_func(int a, int b)
                      {
                          std::cout << sum(a, b) << std::endl;
                      }


                      С «static sum» вывод будет таким:
                      Sum, call_count: 1
                      84
                      Sum, call_count: 1
                      42

                      С «inline sum»:
                      Sum, call_count: 1
                      84
                      Sum, call_count: 2
                      42


                      UPD: ну и помечать static-ом функции, определяемые в заголовочном файле, всё же несколько странно (это же и есть экспортируемый интерфейс).
                      Ответить
                      • >функции, определяемые в заголовочном файле
                        А что странного? ну будет в каждом .c файле своя функция

                        А вообще крестопроблемы же, не?

                        У нас в няшной в .h файлах только декларации обычно
                        Впрочем, инлайновую функцию можно и там определеить.

                        В общем стало понятнее, спасибо
                        Ответить
                        • > А что странного?
                          Ну просто static — это же «внутренняя» функция, и помещать её в публичный интерфейс кажется несколько нелогичным. Но да, это чисто философия, поэтому ничего такого.

                          > А вообще крестопроблемы же, не?
                          Да не, в няшной тоже иногда так хочется. Особенно приятно объявить какую-нибудь инлайн-переменную (так в новых крестах тоже можно), и не ебаться с решением, куда вставлять её определение.

                          Пожалуйста.
                          Ответить
                          • >инлайн-переменную
                            переменную? не константу? ну-ка, попо дробнее
                            Ответить
                            • Да, переменную.

                              // header.h
                              #pragma once
                              #include <iostream>
                              
                              inline int inline_variable;
                              
                              void test_1();
                              void test_2();
                              
                              
                              // test_2.cpp
                              #include "header.h"
                              
                              void test_2()
                              {
                                  std::cout << "inline_variable = " << inline_variable << std::endl;
                              }
                              
                              
                              // test_1.cpp
                              #include "header.h"
                              
                              void test_1()
                              {
                                  std::cout << "inline_variable = " << inline_variable << std::endl;
                              }
                              
                              int main()
                              {
                                  inline_variable = 1;
                                  test_1();
                                  inline_variable = 2;
                                  test_2();
                              
                                  return 0;
                              }
                              // Вывод:
                              // inline_variable = 1
                              // inline_variable = 2
                              Ответить
                              • я понял, хотя красота решения так себе.
                                Где-то в глобальном скопе лежит волатльная хуйня, и ну её нахуй кмк
                                Ответить
          • specially for you with love 🙂

            template <class Arg1>
            constexpr void log_req(Arg1&& arg1)
            {
                if constexpr (std::is_enum_v<Arg1>)
                {
                    std::cout << static_cast<int>(arg1);
                }
                else
                {
                    std::cout << arg1;
                }
            }
             
            template <class Arg1, class... Args>
            constexpr void log_req(Arg1&& arg1, Args&&... args)
            {
                std::cout << arg1;
                log_req(args...);
            }
             
            template <class... Args>
            void log(Args&&... args)
            {
                log_req(args...);
                std::cout << std::endl;
            }
            Ответить
            • Универсальные ссылки в данном случае всё же излишни, достаточно старого доброго «const Arg1 & arg1».
              Ответить
          • а вообще ты мне жизнь сломал... ведь я свято верил что инлайн инлайнит ....
            Ответить
              • Представь как скучно в джаве живется. Все предсказуемо.
                А в крестах "по дульному отсвету определяешь какую ногу отстрелил"
                Ответить
                • В джаве любую задачу принято решать огромным количеством максимально тупого бойлерплейта. Так и живут.
                  Ответить
            • И при этом он инлайнит то что не помечено инлайном.
              Ответить
                • Он может одновременно инлайнить и не инлайнить: инлайнить в конкретном вызове, чтобы оптимизировать скорость выполнения, и оставить незаинлайненную версию, потому что ты взял указатель.
                  Ответить
  • а можно эту херню тупо "регексом" забадяжить :)?
    Ответить

Добавить комментарий

Переведи на "PHP", guest!

    А не использовать ли нам bbcode?


    8