Привет Хабр, я хочу рассказать о творении, на которое потратил свою молодость, уж лучше бы пил и курил.

Msvcore – это кроссплатформенная библиотека для c++, написанная с нуля по принципам оптимальности, открытости и простоты. По крайней мере, это закладывалось как базовая идея. Что получилось в итоге…

Немного истории


Все началось в далеком 2004 году, когда я начал работать кем-то вроде сисадмина на все руки, а заодно начал увлекаться c++. И, как сейчас помню, MFC с его шаблонами и строки CString. Тогда и возникла мысль написать свои строки, простые и понятные. И понеслось.

К сожалению у меня сохранился лишь архив от октября 2005, по нему и буду восстанавливать события. Взглянуть на него вы можете на гитхабе. Самая ранняя дата в архиве датируется 10 октября 2004, за неимением другого, этот день и можно считать днем рождения библиотеки (Date: Sun, 10 Oct 2004 12:50:42 GMT).

Интересно, что библиотека, в отличие от других, создавалась путем эволюции. В нее добавлялся часто используемый код, и дописывалась она под текущие задачи. Задачи усложнялись, библиотека росла. Но в этом есть и минус, вы можете не найти функций, которые, казалось бы обязаны быть в каждой библиотеке. По тому она и велосипед, который дописывается в процессе разработки.

Первым компонентом в моей библиотеке был класс строк MString, полное название MyString.

class MString{ 
	char * data; // Указатель на данные
	unsigned int sz; // Размер строки
	unsigned int rsz; // Размер выделенной памяти
}

Бинарные строки, с одним буфером, заканчивающиеся дополнительным нулевым байтом, который требовался для большинства стандартных функций: open, strlen(), …

После первой большой программы, со статическими массивами, нелогичной логикой и прочими косяками начинающего программиста, потребовались динамические массивы. Общее название первых динамических массивов — MMatrix. Основной принцип: Родительский элемент с указателями на первый и последний элементы массива и, счетчик элементов. Элементы массива имели указатели на предыдущий, следующий элементы и данные. Для каждого варианта данных делалась своя копия класса. Шаблоны? Нет, не слышали. В последствии, классы массивов разрабатывались чуть ли не раз в год.

Так же одним из первых был создан класс MSVCF для работы с конфигурационными файлами.
Писались свои аналоги стандартный функций: itos() и stoi(), itos64() и stoi64(), ftos() и stof() для перевода числа в строку и обратно для int, int64, float. itob() и btoi() тоже, но для бинарных строк. stos() конвертор short в char. explode() для разбиения строки на части. rts() (read to sumbol) и компания, для поиска символа/строки в строке. Создан класс ILink, который потребовался для разбора путей и ссылок на части и используется до сих пор. В какой-то момент потребовался класс IHeader для работы с http заголовками. До сих пор актуален набор функций MSVThreads для создания новых потоков. Создан класс MTime для работы со временем.

Это были зачатки библиотеки, которой еще много предстоит пройти. Объем текста в библиотеке 115кб.

Базовые принципы


Библиотека затачивалась на оптимальность, понятность, логичность и много других хороших слов. На деле, она до сих пор полна страшного кода, написанного в одну строку. Лишь в прошлом году код начал писаться с расстановкой отступов между знаками.

Для использования библиотеки нужно включить в проект два файла MString.cpp и VString.cpp. Попытки подключать библиотеку в виде подключаемого модуля провалились ввиду сложности постоянно пересобирать два проекта вместо одного. Так же, в подключаемой библиотеке нельзя применить изменения на лету. Изначально библиотека включалась в сам проект, но со временем сборка начала занимать продолжительное время, поэтому была разделена на части, чтобы при изменении требовалось пересобрать лишь часть проекта. Проекты на основе библиотеки обычно состоят из трех главных файлов: ProjectName.cpp, MString.cpp, VString.cpp. Код программы пишется в ProjectName.cpp, следующие два подключаются из библиотеки. Здесь часто не используется стандартное разделение кода на cpp и h файлы, для ускорения написания кода. Библиотека и программы порой писалась днями и ночами, и лишние задержки были не к чему.

Слово о кроссплатформенности. После знакомства с линуксом в 2006 году библиотека была допилена для сборки в gcc. Потом под WinCE, Android(Jni) и даже Flash(Crossbridge). Стоит заметить, что все программы изначально пишутся в Windows и MSVS и, лишь потом переносятся на конечную платформу для дописывания платформозависимой части и тестирования. Что экономит уйму времени и сил.

Я принципиально не использовал библиотеки, за исключением тех, которые бессмысленно и сложно переписывать: zlib, openssl, pcre, mysql.

Строки


Концепция строк выстраивалась довольно долго. Варианты с использованием счетчика ссылок, когда несколько переменных указывают на один блок памяти, работали не достаточно оптимально, для них требовалось использовать блокировки и более сложная логика, а в те времена я делал серьезный упор на экономии и простоте.

В какой-то момент появились виртуальные строки VString, сначала как отдельный класс, а впоследствии, решая проблему конвертации строк между классами, как базовый.
В итоге, на сегодняшний день картина такова:

Класс VString (Virtual String) – виртуальные строки, содержит указатель на данные и их размер. Класс не работает с выделением/освобождением памяти. Позволяет быстро выполнять операции со строками, не требующие изменения данных: получение части строки, поиск по строке. Класс заменяет собой часто используемый указатель на строки char*, оканчивающиеся нулем. Я считаю последний вариант работы со строками не оптимальным и попросту опасным, неверные данные в строке не должны вызывать ошибки. Главная проблема в VString – следить за актуальностью данных, на которые указывает переменная этого класса.

class VString{
public:
	unsigned char *data;
	unsigned int sz;
functions...
};

Класс MString (My String) – стандартные строки с выделением памяти под них. Память перевыделяется при каждом изменении размера строки, что делает использование этих строк крайне медленным. Данные строки следует использовать там, где другие варианты строк не подходят. Используются в роли переменных в классах. Здесь основная проблема – необходимость использования блокировок при доступе из нескольких потоков.

class MString: public VString{ functions... };

Класс SString (Stack String) – строки на стеке. Те же строки, но с выделением памяти на стеке, по умолчанию выделяют 1кб, для строк большего размера используется MString. Огромная скорость, но большой лишний объем. Используются как временные переменные. Рождены в погоне за уменьшением операций выделения/освобождения памяти.

class SStringX : public VString{
	unsigned char sdata[stacksize];
	MString mdata;
functions...
};

Класс HLString (Line String) – хранит строки в цепочке из блоков памяти. По умолчанию выделяются блоки памяти по 4кб или под размер данных. Выделение памяти заранее, ускоряет работу при операциях добавления данных. Класс перегружает оператор + и позволяет писать код в виде: MString text(HLString() + “text” + a + 111); Так же класс выделяет память на стеке, для первого блока памяти, по умолчанию 4кб. Варианты использования: сложение множества строк, чисел в одну строку. Так же часто используется финт ушами для временного хранения строк. HLString ls; VString s = ls.addnfr(“Text”); — Добавляет нефрагментированную строку. Здесь плюсы в выделении/освобождении больших блоков памяти, что гораздо быстрее, чем при использовании MString для того же количества строк.

Класс TString (Temp String, Thread String) – Временные или потоковые строки. Идея, пришедшая лишь год назад, а ей стоило поторопиться лет на пять. В принципе, эта идея построена на HLString, нефрагментированных строках и __thread переменных. Каждый поток имеет свой экземпляр HLString переменной, из чего вытекают интересные перспективы. TString выделяет память в HLString, привязанном к потоку, что определенно быстрее, чем выделение памяти через malloc()/free(). Проблема этого класса в том, что он не освобождает память до уничтожения всех переменных TString. В определенные моменты программы все переменные должны уничтожаться, иначе программа постепенно использует всю доступную память с соответствующими последствиями.

Это пять типов строк, использующиеся мной при написании программ. VString — для работы со строками и фрагментами строк, MString — для хранения данных в классах, SString – для сбора строк из подстрок на стеке, HLString – для сбора больших строк на лету, TString – для временных строк.

Массивы


Первая программа, построенная с использованием статических массивов, показала, что с этим что-то надо делать. С тех пор идея писать массивы приходила чуть ли не каждый год.

MMatrix (My Matrix) – первые попытки работать с указателями, постоянные падения и бесконечный поиск ошибок. Состояли из родительского элемента с указателями на первый и последний элемент массива, и, собственно элементов массива, с указателями на предыдущий и следующий элементы, а так же данные. Размножались простым копированием класса и дописыванием нужных функций. Шаблоны это не наш метод. Так же оптимизировались под задачу: а давайте выкинем указатель на предыдущий элемент и сэкономим целых четыре байта.

LMatrix (Live Matrix) ~ 2007г. – вечно живая, как дедушка Ленин. Вы можете взглянуть на код, но даже мне не хочется в этом копаться и вспоминать, по каким принципам она работала.

UMatrix (Unlimited Matrix) ~2008г. – динамический массив из цепочки блоков памяти с хранением нескольких элементов массива в одном блоке. Умеет объединять все элементы в один блок памяти. Здесь была реализована идея выделять память сразу под блок элементов, сокращая работу с функциями памяти. Для определения свободных/занятых элементов используется битовая маска. Эти идеи будут использоваться в следующих вариантах массивов. Шаблоны все еще не наш метод, но и руками копировать достаточно сложно, поэтому был написан кодогенератор массивов.

IMatrix (Ideal Matrix) ~ 2009г. – вектор, весь массив в одном блоке памяти, при нехватке места перемещается на блок памяти большего размера. Впоследствии оказался малополезен и практически не используется.

OMatrix (Object Matrix) ~2010г. – общей идеей повторяет UMatrix, но если идея первой – цепочка объектов, то здесь идея разделенности. Здесь, в отличие от UMatrix, реализован список свободных объектов и проход по ним. Данный класс используется как аллокатор памяти, позволяя быстро получать/освобождать память под переменные.
Матрицы закончились, начались листы. А вместе с ними были заброшены кодогенераторы и приняты к использованию шаблоны.

MList (My List) ~ 2013г. – Класс автоматически оборачивает пользовательский класс в свой, добавляя указатели на предыдущий и следующий элементы.

IList (Ideal List) ~ 2014г. – IMatrix с заменой кодогенератора на шаблоны, все тот же вектор.

OList (Object List) ~ 2015г. – Аналогично, OMatrix переписанный под шаблоны.

UList (Unlimited List) ~ 2015г. – Замена UMatrix, шаблоны, красивый и логичный код.

AList (Auto List) 2015г. – Динамический массив с набором аллокаторов памяти, от стандартного new/free, UList, HLString, OList до возможности написать свой.

TrieList 2016г. – Реализация Trie дерева для быстрого поиска, на базе AList.

Как это не печально, массивы постепенно обрастают шаблонами, с одной стороны это упрощает разработку, с другой усложняет понимание и изменение под свои задачи.

Использование библиотеки


Простейший пример, создать пустой проект и добавить cpp файл с содержимым:

#define USEMSV_GENERALCPP
#define PROJECTNAME "projectname"
#define PROJECTVER PROJECTNAME ## _versions

#include "../../opensource/msvcore/msvcore.cpp"

Versions PROJECTVER[]={
	// new version to up
	"0.0.0.1", "10.10.2013 21:24"
};

int main(int args, char* arg[]){
	ILink link; mainp(args, arg, link);
	print(PROJECTNAME, " v.", PROJECTVER[0].ver," (", PROJECTVER[0].date, ").\r\n");
return 0;
}

Добавить в проект файлы "..\..\opensource\msvcore\VString.cpp" и "..\..\opensource\msvcore\MString.cpp" и писать код.

При добавлении нескольких cpp файлов следует использовать тот же код до #include … msvcore.cpp включительно, удалив строчку #define USEMSV_GENERALCPP. Так же можно подключать дополнительные расширения библиотеки, указывая их до подключения msvcore.cpp, например #define USEMSV_OLIST дает возможность использовать массивы OList. Список расширений можно увидеть в msvcore.cpp

По умолчанию в библиотеке:

  • Подключаются платформозависимые файлы, определяются различные дефайны.
  • Доступны классы строк: VString, MString, TString, SString(), HLString.
  • Доступны наборы функций: rts() – поиск по строке, PartLine() – аналог для работы с VString.
  • Класс ILink – для работы с путями и ссылками, класс MTime – для работы со временем, класс ConfLine – работа с конфигурационными файлами, класс Logs — для ведения логов, класс MSVEF – аналог регулярных выражений.
  • Класс UList – динамические массивы, класс MMatrix – первые динамические массивы, набор классов MTE универсальных классов для хранения различных типов данных.
  • Класс MRect для работы с регионами, класс MRGB для работы с цветами.
  • Класс mbool – для работы с битовыми масками, функции конвертации строк в числа, кодировки, различные форматы и наоборот.
  • Наборы библиотек под wince, flash.
  • Набор кроссплатформенных функций для работы с файлами: CreateFile(), ReadFile(), WriteFile(), GetFilePointer()… GetFileInfo(), CloseHandle(), MkDir(), LoadFile(), SaveFile().
  • Класс Readdir для получения списка файлов в папке, использует MSVEF в качестве фильтра.
  • Функция вывода в консоль print(VString string, VString string1 = VString(), …).
  • Функции для создания потоков StartThread().
  • Классы блокировки: TLock – критические секции, CLock – condition variables / условные переменные, UGLock – автоматическая блокировка/разблокировка TLock.
  • Классы работы с буферами: SendDataL – линейный буфер, SendDataRing – кольцевой буфер, RecvData – буфер для приема данных.
  • Классы работы с сетью: ConIp – для установки соединения и открытия порта. Функции: GetIP() – получение ip по имени домена, ifrecv() – проверка доступности данных в сокете, ifsend() – проверка разрешения на запись в сокет, gettip() и getcip() – возвращает ip и порт, сервера и клиента.

Дополнения, указываются перед включением msvcore.cpp:

#define USEMSV_ITOS
Класс ITos, предыдущая версия SString. Устарел.

#define USEMSV_INTERCEPT
Набор функций для анализа машинных кодов и перехвата функций.

#define USEMSV_CPPXCC
Класс XCC – парсер кода на C++.

#define USEMSV_INTERCEPT_MALLOC
Код для перехвата системных функций работы с памятью, используется для поиска утечек памяти.

#define USEMSV_XDATACONT
Классы для работы с форматами данных. Класс XDataCont разбирает JSON и XML, остальные классы устарели.

#define USEMSV_CJX
Класс CjxCont с реализацией бинарного формата данных, бинарный json.

#define USEMSV_MLIST, USEMSV_ILIST, USEMSV_OLIST, USEMSV_ALIST, USEMSV_TRIELIST
Подключает соответствующие классы динамических массивов: MList, IList, OList, AList, TrieList.

#define USEMSV_AMF
Классы amfe и amfd для конвертирования/разбора AMF формата.

#define USEMSV_PCRE
Подключает библиотеки с функциями регулярных выражений pcre2.

#define USEMSV_CONSOLE
Классы PipeLine и PipeLine2 для запуска других процессов.

#define USEMSV_MWND
Практически отдельная библиотека для работы с окнами, графикой, изображениями. Позволяет работать с графикой на всех поддерживающих библиотекой платформах. Содержит функции рисования примитивов, не зависящие от платформы. Про нее стоит рассказывать отдельно. Использует библиотеку CxImage для кодирования/декодирования форматов изображений.

#define USEMSV_CONSOLELINE
Набор классов для работой с консолью.

#define USEMSV_OPENSSL
Функции и классы для работы с openssl и шифрованием. Класс MySSL для установки/приема ssl соединений и работы с ними. Функции: RsaCreateKeys() – создает два Rsa ключа, функции RsaPublicEncode(), RsaPublicDecode(), RSAPrivateEncode(), RsaPrivateDecode() – шифруют/расшифровывают открытым/закрытым ключом, функции AesEncode() и AesDecode() кодируют/декодируют алгоритмом Aes. Так же содержит функции работы с сертификатами.

#define USEMSV_WEBSOCKETS
Набор функций для работы с WebSockets и класс WebSocketsCli – реализация WebSockets клиента.

#define USEMSV_MYSQL
Класс MySQLCon — обертка для работы с MySQL, использует mysql-connector-c.

#define USEMSV_MSL_FL
Подключает интерпретатор MSL – мой вариант языка программирования, больше всего напоминающий php. Msl Fast Line – 4 версия msl. Без генерации псевдокода, выполняет текстовые команды. Написан где-то за неделю в октябре 2013. Про него тоже стоит рассказывать отдельно.

#define USEMSV_MSL_FV
Msl Five – пятая версия языка. С генерацией байт кода и прочими плюшками. Разрабатывалась в сентябре 2015 года.

#define USEMSV_HTTP
Классы и функции для работы с http запросами. Классы GetHttp и GetHttp2. При подключении openssl функций поддерживает https запросы. Класс IHeader для работы с http заголовками. Класс MCookie для работы с куками.

#define USEMSV_CONFLINE
Класс ConfLineOptions для работы с конфигурационными файлами.

#define USEMSV_NESTAPI, USEMSV_NESTAPI2
Классы и функции для серверной части моего протокола NestApi.

#define USEMSV_STORMSERVER
Серверная платформа, о которой я бы хотел написать отдельный пост. Порядка десяти лет я пытался писать хорошие сервера и это наконец то удалось. Практически идеальное решение.

#define USEMSV_LIGHTSERVER
Класс LightServer — простой и легкий сервер, под который можно написать свой обработчик. Класс LightServerHttp – простой https сервер, возвращающий тестовую страничку.

#define USEMSV_TGBOTS
Классы TgBot и TgBots реализация ботов для телеграмма.

#define USEMSV_ANDROID
Функции и классы упрощающие работу при компиляции под андроид.

#define USEMSV_TRAFFIX
Классы для прослушивания трафика.

#define USEMSV_BUFECHO
Функции для изменения опций консоли.

Заключение


Надеюсь, вас заинтересует этот велосипед имени меня и мне будет, что рассказать вам еще. На мой взгляд, здесь есть довольно интересные вещи, начиная со строк, массивов, написаны обертки для openssl, может заинтересовать msl, или класс для создания ботов в телеграмме, и наконец, stormserver – платформу для создания различных серверов. Про последний я напишу отдельную статью, о разработке серверов, от простого эхо сервера до сложных http и прокси.

Как я уже говорил, библиотека довольно сильно смещена в сторону разрабатываемых программ. Как показывает практика, саму по себе ее сложно разрабатывать, не имея конкретных задач.

Я писал эту библиотеку для того, чтобы научиться хорошо программировать и понимать, что делает код от начала и до конца. И, надо сказать, прогресс есть, но еще работать и работать.

В дальнейших планах еще раз переписать с нуля, окончательно избавиться от старого кода, привести в порядок. И возможно, наконец-то написать документацию. Так же в планах дописать реализацию новых вариантов строк, как замену текущим, и, новые динамические массивы.

> Код библиотеки и несколько проектов
Поделиться с друзьями
-->

Комментарии (40)


  1. staticlab
    27.11.2016 13:26
    +9

    У вас


    • не указана лицензия на код;
    • непонятно, как собирать библиотеки;
    • все проекты объединены в один репозиторий;
    • нет документации;
    • стиль кода оставляет желать лучшего;
    • куча опечаток в коде;
    • много реализации в хедерах.


    1. lookid
      27.11.2016 13:36
      +10

      И, скорее всего, абсолютно не применима на продакшене


      1. MikelSV
        28.11.2016 00:40

        В принципе применима. Использую библиотеку почти во всех своих проектах. Скорее ее сложно использовать по ряду очевидных причин, типа отсутствия документации и сложности понимания.


        1. lookid
          28.11.2016 13:54

          Я не говорю, что она плохая.
          https://github.com/yandex/ClickHouse
          вот пример другой опенсорсной либы


    1. domix32
      27.11.2016 15:15
      +6

      С учетом того что библиотеку предлагают подключать при помощи cpp реализация в хедерах не выглядит чем-то из ряда вон


    1. MikelSV
      28.11.2016 00:35

      Да, вопрос с лицензией упустил. Исправлюсь, выберу подходящую. Сейчас о лицензии написано только в https://github.com/mikelsv/opensource/blob/master/msvcore/msvcore.cpp:

      Лицензия популяризации автора. :]
      Вы не должны изменять имя и другую информацию о разработчике и не присваивать авторство себе.
      Не продавать и не брать денег за код из данной библиотеки.
      Разрешается модифицировать и дорабатывать.
      Код предоставлен как есть и автор не отвечает, даже если вы попытаетесь прострелить себе ногу.

      Библиотека не собирается, она подключается в проект в виде кода. Пример минимального проекта приведен в посте. (#define USEMSV_GENERALCPP...)

      Все проекты в одном репозитории сделаны для удобства переноски и сборки на других машинах. Часто код пишется на одной машине и отлаживается на другой. Обновлять два репозитория дольше, чем один. Не сильно, но при активной разработке это отнимает время. В планах разнести библиотеку и проекты по разным репозиториям.

      Да, документация больной вопрос. Хорошая документация требует достаточных сил, которые обычно тратятся на улучшение библиотеки. Постараюсь пересмотреть приоритеты и начать заниматься документацией.

      Стиль кода со временем улучшается. Старый код переписывается. Движемся в нужном направлении.

      Не очень понятно про опечатки. Можно примеры?

      В какой-то момент код начал писаться и в .cpp и в .h. Компиляторам все равно, с людьми сложнее. Вопрос тоже требует рассмотрения и переработки библиотеки.


      1. staticlab
        28.11.2016 00:57

        Пожалуй, к списку своих претензий могу добавить лицензию и кодировку.


        Если предполагается, что библиотека будет использоваться не только автором, то её API должен быть продокументирован как можно более подробно. Ну хотя бы надо сделать описания классов и функций в формате doxygen. Ещё хороший способ показать, как использовать код — написать юнит-тесты. Убиваем сразу двух зайцев.


        Насчёт опечаток:


        #define MSTRING_TEMPALTE_ADD5
        unsigned char times_new_romain[]=
        int Reserv(int sz){
        int Analys(){
        ...


        1. MikelSV
          28.11.2016 12:10

          Действительно, настолько привык, что не замечаю очевидных ошибок.

          Мне подсказали статьи про опенсорс и составление документации. Рассчитываю, что они помогут как минимум с документацией, а как максимум со всем остальным.


  1. Halt
    27.11.2016 14:05
    +7

    Ну я даже не знаю

    // free to lists
    if(!fre){ globalerror("OMATRIX2 !fre"); return 0; }
    int num=fre->getfree(); usesz++; if(num<0 || num>=newsz){ globalerror("OMATRIX2 num>maxsz"); return 0; }
    PROCSTRUCTCN *el= ((PROCSTRUCTCN*)(fre->data)) + num;
    fre->u++; fre->set(num, 1);
    new(el)PROCSTRUCTCN;
    

    P.S.: А еще ни одного ассерта.


    1. encyclopedist
      27.11.2016 14:34

      В приведенном фрагменте целых 2 ассерта же.


      1. Halt
        27.11.2016 14:37

        Я говорю про контракты.


    1. MikelSV
      28.11.2016 00:56
      -1

      Этот класс устарел и в следующей версии библиотеки будет заменен. Новый класс написан и тестируется.

      Признаться, не использую ASSERT(). Насколько помню, в Windows он вызывает окно и программа встает. Вместо них использую globalerror() которая выведет сообщение в консоль. При фатальной ошибке программа продолжит работать дальше.


      1. staticlab
        28.11.2016 00:58
        +3

        У вас случилась фатальная ошибка, а вы хотите продолжать дальше?


        1. MikelSV
          28.11.2016 12:03

          Фатальная ошибка для одного класса часто не фатальна для программы. Ошибки часто возникают, когда программа запущена, а меня нет рядом. В такой ситуации лучше, чтобы программа хоть как-то доработала, до того как я смогу ее починить.


          1. encyclopedist
            28.11.2016 18:57

            Во многих случаях лучше упасть, чем выдать неправильный результат. Особенно если это касается инвариантов, которые по алгоритму не могут нарушиться никогда. Возможно, стоит позволить пользователю решать, какое поведение ему нужно.


      1. infrapro
        28.11.2016 15:22
        +1

        в Windows он вызывает окно и программа встает.

        Только в дебаг режиме, в релизе макрос ASSERT ничего не делает


  1. semenyakinVS
    27.11.2016 14:13
    +5

    Комментарии навскидку. Позже напишу ещё вопросы.

    Набор функций для анализа машинных кодов и перехвата функций

    Код для перехвата системных функций работы с памятью, используется для поиска утечек памяти

    начиная со строк, массивов, написаны обертки для openssl, может заинтересовать msl, или класс для создания ботов в телеграмме, и наконец, stormserver – платформу для создания различных серверов


    Вот это разнообразие… Разнообразие, которому буст позавидовал бы. Но проблема в том, что чтобы понять насколько всё написанное имеет смысл — такой статьи мало. Чтобы кто-то серьёзно рассматривал код, навелосипеденый за десять лет, нужно доказать необходимость существования этого кода. Нужны сравнения какие-то по метрикам: расходы ресурсов компа (память, CPU, и т.д.) и/или людей (время на чтение кода, удобство API, и т.д.). Учтите, что метрики, касающиеся людей, будут субъективны и чтобы вам кто-то поверил стоит очень хорошо сформулировать что выводится под ними.

    Я бы на вашем месте перед тем, как публиковать подобную обще-обзорную статью, написал для пробы подробную статью о каком-нибудь одном подмодуле. С вескими доказательствами зачем это вообще нужно.
    Если возьмётесь за такое — было бы интересно почитать про строки (если они поддерживают разные кодировки — UTF-8, UTF-16, и т.д.). Я бы такую статью почитал с интересом, данная тема в плюсах хромает.

    Класс XCC – парсер кода на C++


    Вот это заявка… Вы действительно сами написали парсер С++ с нуля? Я просто в какой-то момент начинал таким заниматься — очень немного, к счастью, начинал. И это… Как сказать, это задача, о которую можно убиться. Серьёзно. Лучше clang покурить. Там достаточно разумно всё устроено.


    1. MikelSV
      28.11.2016 01:18

      Это скорее обзорная статья, обо всем и ни о чем. Сказать, что есть такая библиотека, узнать реакцию и узнать, что в ней может быть интересно другим людям. В следующих постах я планирую рассказывать уже о конкретных модулях.

      Строки. Хм. У меня тема кодировок тоже хромает. Когда нужно, использую функции преобразования одного формата в другой. Какой-то общей проблемы или задачи я не вижу. С одной стороны тема интересная, с другой, я пока не понимаю, что в итоге требуется получить.

      Про парсер C++, возможно мы понимаем разное под парсером. Моя реализация работает как препроцессор, обрабатывает #if #ifdef #define #endif… и разбирает код на части. Насколько я помню у меня нет анализа типов или чего-то большего. В принципе, можно как-нибудь заняться и дописать анализ типов, классов и всего остального.


      1. semenyakinVS
        28.11.2016 02:22

        Думаю, вы сами видите комментарии. Люди негодуют. На мой взгляд, всё было бы совсем по-другому, если бы вы подробно описали в статье какую-нибудь вкусность библиотеки и там, в самом конце, приписали бы, что, мол «у меня есть добавка, чего желаете». Опросник бы прикрутить могли, вроде «что ещё интересно»…

        Ну и, конечно, вот такое писать некрасиво. При публикации кода и/или библиотеки ставьте себя хоть немного на место читателей.


    1. metopa
      28.11.2016 09:20
      +2

      Касательно парсера, там всё серьёзно (форматирование сохранено)

      #define AA(a) int a;
      #define B(b) AA(b)
      
      #define A 1, 2, 3
      #define B(a, b, ...) printf(a, __VA_ARGS__ );
      	B("%d %d %d\r\n", 1, 2, 3);
      	B("%d %d %d\r\n", ::A);
      
      	#define B fail
      	#define BB(a, b, c) a c
      	#define AB(B) BB(B)
      	AB(A);
      
      	#define BC(a, b, c) a c
      	#define AC(B) BC(::B)
      
      	AC(A);
      


  1. semenyakinVS
    27.11.2016 14:24

    Что касается мегауниверсальных библиотек вообще… Я тоже веду библиотеку с функционалом, общим для всего множества проектов. Там есть и строки, и коллекции, и события всякие, и парсеры… Вообще очень много чего ещё, короче.

    Но фишка в том, что большинство этих классов выступают обёртками вокруг существующих библиотек — от stl до rapidxml. Во-первых, такой подход позволяет экономить кучу времени на детали реализаций, во-вторых, даёт возможность в случае необходимости менять реализации (в том числе на полностью свои, если будет нужно) без переделки кода всех проектов, использующих библиотеку… Ну, и в-третьих, при правильно использовании С++, такой подход почти бесплатный с точки зрения затрат ресурсов компьютера.

    Меня описанная организация проектов устраивает. Читающие комментарий, как по-вашему, подобная организация нормальная и жизнеспособна, или вы какие-то другие подходы используете?


  1. FoxCanFly
    27.11.2016 14:53
    +13

    Ну автору хотя бы в смелости не отказать, выносить подобное на публичный суд без тени смущения :)
    PS. Тут просто сборник самых жутких антипаттернов и просто дичи.


    1. Sayonji
      27.11.2016 15:52
      +3

      Автор это написал для инвайта, я не уверен, что он рассчитывал, что кто-то всерьез будет смотреть в код. Даже начинается статья так:

      Msvcore – это кроссплатформенная библиотека для c++, написанная с нуля по принципам оптимальности, открытости и простоты.

      Что такое msvcore? — Библиотека. Что она делает — уже не так важно.


      1. MikelSV
        28.11.2016 01:33

        Автор все-таки надеялся, что библиотекой начнет пользоваться кто-нибудь еще, кроме него.
        Признаться, мне показалось, что тут целый пост о том, что она делает. Уместить описание в одну строчку мне к сожалению не удалось.


  1. Sayonji
    27.11.2016 15:48
    +14

    Вот это я понимаю документация.

    LMatrix (Live Matrix) ~ 2007г. – вечно живая, как дедушка Ленин. Вы можете взглянуть на код, но даже мне не хочется в этом копаться и вспоминать, по каким принципам она работала.

    Пользуйтесь на здоровье.


    1. MikelSV
      28.11.2016 01:39
      -1

      Это пример того, чем не надо пользоваться. Присутствует исключительно для истории.


  1. lastmac
    27.11.2016 17:00
    +3

    Завидую вашей энергии.
    Но всё это походит на код написаный из головы, побыстрому и на коленке. Если бы в начале каждого файла был комментарий:

    /* это заглушка для попробовать, дальше надо решить писать основательно или нет */
    
    то всё встало бы на свои места.

    К слову, писал три года драфт хтлм рендера на Си, вот он примерно так же выглядит. Я достиг нужного мне результата (изучил спецификации, понял тонкие места, проблемы и прочее), и вот только теперь пишу «в чистовик» который в открытом доступе. Но делится с общественностью подобным драфтом я бы ни в коем случаи не стал, и люди не поймут, и вообще, надо иметь «чувство прекрасного».

    Я обычно представляю себе серьезную компанию с серьёзным проектом и задаюсь вопросами: а использовала бы она мой код? не возникло бы проблем? мой код решает существующие проблемы? может быть я не до конца познал данную тему/сферу чтобы что-то предлагать своё? — всё это, лично мне, помогает более строго относится к себе и к тому что я делаю.

    Вам успехов в проекте!

    P.S.: позже увидел хаб «ненормальное программирование» и всё встало на свои места.


  1. AxisPod
    27.11.2016 20:27
    +1

    Даже мимолётный взгляд и сразу стало больно. Требуется лютый рефакторинг. Для начала разобраться в stl, затем уже рефакторить. А в таком виде я бы не стал использовать.


    1. MikelSV
      28.11.2016 01:49

      Требуется. Библиотека раза четыре писалась заново с добавлением кода из прошлой версии. И пятый уже на подходе. По мере сил, возможностей и понимания.
      У меня свои подходы и stl принципиально не используется. А иначе половину библиотеки можно выкинуть, а вторую переделывать по принципам stl. Одним словом похоронить.


  1. Ivan_83
    27.11.2016 22:49
    +1

    Хз чего в комментах накинулись на автора, он же написал:
    «Лишь в прошлом году код начал писаться с расстановкой отступов между знаками.»
    и
    «После знакомства с линуксом в 2006 году...»
    «Стоит заметить, что все программы изначально пишутся в Windows и MSVS и, лишь потом переносятся на конечную платформу для дописывания платформозависимой части и тестирования. Что экономит уйму времени и сил.»
    после этого вполне очевидно что ждать там какого то супер кода или каких либо чудес не стоит.

    Я тоже пилю свою либу, года с 2002 но это большей частью всегда была коллекция хэлперов — разных функций которые нужны то тут то там: md5, sha1, sha2, crc32, base64, ecdsa, mem хелперы и пр. Оно прекрасно живёт именно в хидерах: include НУЖНОЕ и готово (хоть в ядре ОС). Поэтому оно в виде библиотеки кода а не готовой либы типа буста/опенссл и пр.
    За это время весь код рефакторился кучу раз: то codestyle то const добавлял то всплывали какие то моменты специфичные для компилятора/ос и я их массово менял-выпиливал. Asm код ушёл почти полностью в угоду переносимости.
    Только последние годы (4-5 лет) начал пилить свой ev движок на kqueue()/epoll().

    Те мне понятно откуда это всё у автора, но не понятно почему автор так долго шёл хотя бы к нормальному codestyle и почему не пришёл к опенсорц ОС за 10.

    Автору бы свалить с винды (чтобы возникли реальные хотелки допилить что то) и поучаствовать в опенсорц, это даст хороший толчок в нужном направлении для саморазвития.

    2 staticlab
    Реализация в хидерах ничем не плоха, из неё получается точно такой же машинный код.
    Главное не злоупотреблять.

    2 FoxCanFly
    Думаешь автору есть какое то дело до того что тут напишут какие то анонимы?
    Вот если бы была опасность хотя бы доходам а то и жизни, вот тогда можно говорить о смелости.

    2 lastmac
    Корпорациям главное бабало, это в большинстве случаев значит получить код как можно быстрее, рабочий и не важно какой он там внутри. (Вин виста, вин 10 — многострадальная :) — под ж устаканится только к еол семёрки в 2020 году).
    И уже потом, когда начинают сами свой код юзать и считают сколько денег уходит на сервера и электричество начинаются оптимизации.
    Большая часть префекционистов пишут опенсорц. Притом на работе могут и говнокодить ибо там время поджимает/задача не интересная/…
    Ровно как и большая часть программистов пишут код который никто никогда не увидит…


    1. staticlab
      27.11.2016 23:05

      Реализация в хедерах плоха тем, что при использовании в cpp двух хедеров, каждый из которых подключает хедер с реализацией, будет ошибка компиляции. Разумеется, шаблоны — это особый случай.


    1. staticlab
      27.11.2016 23:07
      +2

      Позанудствую

      Правильно говорить «хэдер», потому как head (голова) читается всё же как «хэд», а не «хид».


  1. ZaMaZaN4iK
    27.11.2016 22:55

    Лично меня интересует именно реализация Trie в этой библиотеке. Если она оптимальная, то я пожалуй перетащу её частями в Boost.Trie. Если у кого есть красивая и быстрая реализация trie — просьба поделиться.


    1. MikelSV
      28.11.2016 02:19

      В Boost нет Trie?
      Ммм, все зависит от того, что вам нужно. Это достаточно оптимальная, но не самая быстрая реализация. Для ускорения поиска сюда стоит добавить хеш таблицу или lower bound. Так же у меня реализация многоуровнего дерева(одно дерево может содержать другое), сделанная для быстрого поиска по JSON.

      Это все нужно обсуждать. И основываясь на понимании логики Boost, которой у меня к сожалению нет, и на задачах, которое должно решать Trie, писать логику. Это для самого шустрого и оптимального варианта. Для остальных, можно взять текущий: https://github.com/mikelsv/opensource/blob/master/msvcore/list/TrieList.h


  1. rawf
    28.11.2016 02:20

    а чем это лучше STL?


    1. MikelSV
      28.11.2016 02:28

      Отсутствием дикого количества шаблонов и сложной логики. Я стараюсь писать максимально простой код, хотя и не всегда удается.


  1. metopa
    28.11.2016 02:29
    +3

    Как это не печально, массивы постепенно обрастают шаблонами, с одной стороны это упрощает разработку, с другой усложняет понимание и изменение под свои задачи.

    Можете показать как шаблоны могут усложнить изменение под свои задачи?
    И вы, конечно, извините, но после 12 лет разработки на плюсах писать, что шаблоны усложняют понимание, как минимум, странно.


    1. MikelSV
      28.11.2016 02:54

      Там были свои финты ушами, когда исправлялся каждый класс массива, под свою задачу. С шаблонами так не сделаешь, да и не надо.
      Возможно я недостаточно работал с шаблонами и для меня их использование запутывает код. Начал больше писать шаблонные классы и ситуация понемногу исправляется.
      К сожалению в шаблонах stl я до сих пор ориентируюсь довольно хреново.


      1. metopa
        28.11.2016 09:15
        +3

        Думаю, когда наконец-то освоите их, захотите переписать всю библиотеку ещё раз. Шаблоны — вещь!
        Кстати, тонкая настройка реализации тоже шаблонами на ура решается (почитайте про специализацию шаблонов и traits классы).


      1. staticlab
        28.11.2016 20:59

        С шаблонами так не сделаешь
        в шаблонах stl я до сих пор ориентируюсь довольно хреново

        Лучше уж шаблоны, чем макросы