msvcore-C ++、クロスプラットフォームライブラリ、自転車、および12年間の開発

こんにちはHabr、私は自分の若さを費やした創造について話をしたい、それは飲むと喫煙する方が良いでしょう



Msvcoreは、c ++のクロスプラットフォームライブラリであり、最適性、オープン性、シンプルさの原則についてゼロから記述されています。 少なくともそれは基本的なアイデアとして築かれました。 最後に何が起こったのか...



ちょっとした歴史



それはすべて、2004年にすべての取引のシステム管理者のような人と仕事を始めたときに始まり、同時にc ++に関与し始めました。 そして、今覚えているように、MFCにはテンプレートとCString文字列があります。 その後、シンプルでわかりやすい独自の行を書くというアイデアが生まれました。 そして去ります。



残念ながら、私は2005年10月からアーカイブのみを保持し、そこからイベントを復元します。 githubで見ることができます。 アーカイブの最初の日付は2004年10月10日で、別の日付がない場合、この日はライブラリの誕生日と見なすことができます(日付:2004年10月10日12:50:42 GMT)。



興味深いことに、ライブラリは他とは異なり、進化によって作成されました。 頻繁に使用されるコードが追加され、現在のタスクに追加されました。 タスクがより複雑になり、ライブラリが成長しました。 しかし、これにはマイナス点があり、すべてのライブラリに必要な関数が見つからない場合があります。 したがって、開発プロセスで追加される彼女とバイク。



ライブラリの最初のコンポーネントはMString文字列クラスで、フルネームはMyStringです。



class MString{ char * data; //    unsigned int sz; //   unsigned int rsz; //    }
      
      





ほとんどの標準関数に必要な、余分なヌルバイトで終わる1つのバッファを持つバイナリ文字列:open、strlen()、...



静的配列、非論理的ロジック、および初心者プログラマーのその他の妨害を伴う最初の大規模なプログラムの後、動的配列が必要になりました。 最初の動的配列の共通名はMMatrixです。 基本原則:配列の最初と最後の要素へのポインターと、要素のカウンターを持つ親要素。 配列の要素には、前、次の要素およびデータへのポインタがありました。 データの各バージョンは、クラスの独自のコピーになりました。 テンプレート? いいえ、聞いていません。 その後、配列クラスはほぼ1年に1回開発されました。



MSVCFクラスを最初に作成したものの1つは、構成ファイルを操作することでした。

標準関数の類似物が作成されました:数値を文字列に変換し、int、int64、floatに戻すためのitos()およびstoi()、itos64()およびstoi64()、ftos()およびstof() itob()およびbtoi()もバイナリ文字列用です。 stos()短いcharコンバーター。 explode()は、文字列を部分に分割します。 rts()(sumbolに読み取られる)およびcompany。文字列内の文字/文字列を検索します。 ILinkクラスが作成されました。これは、パスとパーツへのリンクを解析するために必要であり、現在も使用されています。 ある時点で、IHeaderクラスがhttpヘッダーを処理する必要がありました。 新しいスレッドを作成するためのMSVThreads機能セットは引き続き関連しています。 MTimeクラスは、時間とともに機能するように作成されています。



これらはライブラリの始まりでしたが、まだまだ多くのことがあります。 ライブラリ内のテキストのボリュームは115kbです。



基本原則



ライブラリは、最適性、わかりやすさ、論理、その他の多くの良い言葉で研ぎ澄まされました。 実際、まだ1行で書かれた恐ろしいコードでいっぱいです。 昨年だけ、コードは文字間インデントで記述され始めました。



ライブラリを使用するには、プロジェクトに2つのMString.cppファイルとVString.cppファイルを含める必要があります。 ライブラリをプラグインとして接続しようとすると、1つではなく2つのプロジェクトを絶えず再組み立てすることが困難なため失敗しました。 また、プラグインライブラリでその場で変更を適用することはできません。 当初、ライブラリはプロジェクト自体に含まれていましたが、時間が経つにつれてアセンブリが長時間かかり始めたため、パーツに分割されたため、変更時にはプロジェクトの一部のみを再構築する必要がありました。 ライブラリベースのプロジェクトは通常、ProjectName.cpp、MString.cpp、VString.cppの3つのメインファイルで構成されます。 プログラムコードはProjectName.cppで記述され、次の2つはライブラリから接続されます。 これは、コードの記述を高速化するために、cppファイルとhファイルへの標準的なコード分離を使用しないことがよくあります。 ライブラリとプログラムは、日中と夜間に作成されることがあり、追加の遅延は必要ありませんでした。



クロスプラットフォームについての言葉。 2006年にLinuxに会った後、ライブラリはgccでのアセンブリ用にダビングされました。 次に、WinCE、Android(Jni)、さらにはFlash(Crossbridge)の下で。 すべてのプログラムは最初にWindowsとMSVSで作成され、その後プラットフォームに依存する部分を追加してテストするために最終プラットフォームに転送されることは注目に値します。 これは多くの時間と労力を節約します。



私は基本的にライブラリを使用しませんでしたが、無意味で書き換えが難しいライブラリを除きます:zlib、openssl、pcre、mysql。





線の概念は長い間構築されてきました。 参照カウンターを使用するオプションは、複数の変数が同じメモリブロックを指している場合、十分に最適に機能せず、ロックとより複雑なロジックを使用する必要があり、当時は経済とシンプルさを重視していました。



ある時点で、VString仮想文字列は、最初は別個のクラスとして現れ、その後、基底としてクラス間で文字列を変換する問題を解決しました。

その結果、今日の状況は次のとおりです。



クラスVString (仮想文字列)-仮想文字列には、データへのポインターとそのサイズが含まれます。 このクラスは、メモリの割り当て/割り当て解除では機能しません。 データの変更を必要としない文字列を使用して、文字列の一部を取得したり、文字列を検索したりする操作をすばやく実行できます。 このクラスは、ゼロで終わるchar *文字列への一般的に使用されるポインターを置き換えます。 文字列を操作するための最後のオプションは最適ではなく、単に危険であると考えています;文字列内の不正なデータはエラーを引き起こすべきではありません。 VStringの主な問題は、このクラスの変数が指すデータの関連性を追跡することです。



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





クラスMString (My String)-それらにメモリが割り当てられた標準文字列。 行のサイズが変更されるたびにメモリが再割り当てされるため、これらの行の使用は非常に遅くなります。 これらの文字列は、他の文字列オプションが適さない場合に使用する必要があります。 クラスの変数として使用されます。 ここでの主な問題は、複数のスレッドからアクセスするときにロックを使用する必要があることです。



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





SStringクラス(スタック文字列)は、スタック上の文字列です。 同じ行ですが、スタック上のメモリ割り当てでは、デフォルトで1kbが割り当てられ、MStringはより大きな行に使用されます。 素晴らしい速度ですが、大量の追加容量があります。 一時変数として使用されます。 メモリ割り当て/割り当て解除操作の削減を目指して生まれました。



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





クラスHLString (Line String)-文字列をメモリブロックのチェーンに格納します。 デフォルトでは、4kbのメモリブロックまたはデータサイズが割り当てられます。 事前にメモリを割り当てると、データ追加操作の操作が高速化されます。 このクラスは+演算子をオーバーロードし、次の形式でコードを記述できるようにします。MString text(HLString()+“ text” + a + 111); また、このクラスは、最初のメモリブロック(デフォルトでは4kb)にスタック上のメモリを割り当てます。 ユースケース:多くの行の追加、1行の数値。 それはまた、一時的に文字列を保存するためにフェイントイヤーによってよく使用されます。 HLString ls; VString s = ls.addnfr(「テキスト」); -断片化されていない行を追加します。 大きなメモリブロックの割り当て/解放には利点があります。これは、同じ行数でMStringを使用するよりもはるかに高速です。



クラスTString (一時文字列、スレッド文字列)-一時文字列またはストリーミング文字列。 ほんの1年前に思いついたアイデアで、彼女は5年間急いでいた。 基本的に、このアイデアはHLString、断片化されていない文字列、および__thread変数に基づいています。 各スレッドにはHLString変数の独自のインスタンスがあり、そこから興味深い見通しが生まれます。 TStringは、スレッドにバインドされたHLStringにメモリを割り当てます。これは、malloc()/ free()を使用してメモリを割り当てるよりも確実に高速です。 このクラスの問題は、すべてのTString変数が破棄されるまでメモリを解放しないことです。 プログラムの特定の時点で、すべての変数を破棄する必要があります。そうしないと、プログラムは使用可能なすべてのメモリを徐々に使用して、対応する結果をもたらします。



これらは、プログラムを作成するときに使用する5種類の行です。 VString-文字列と文字列フラグメントを操作するため、MString-クラスにデータを保存するため、SString-スタック上の部分文字列から文字列を収集するため、HLString-大規模な文字列をオンザフライで収集するため、TString-一時的な文字列用



配列



静的配列を使用して構築された最初のプログラムは、これで何かを行う必要があることを示しました。 それ以来、ほぼ毎年配列を書くというアイデアが浮上しています。



MMatrix (My Matrix)-ポインター、絶え間ないクラッシュ、エラーの無限の検索を扱う最初の試み。 それらは、配列の最初と最後の要素へのポインタを持つ親要素と、実際には、データと同様に前と次の要素へのポインタを持つ配列の要素で構成されていました。 クラスをコピーして必要な機能を追加するだけで伝播されます。 テンプレートは私たちの方法ではありません。 また、タスク用に最適化しました。ただし、前の要素へのポインターを捨てて、4バイトも保存します。



LMatrix (ライブマトリックス) 〜2007 -祖父レーニンのように、永遠に生きています。 コードを見ることができますが、私がそれを掘り下げて、どの原則に取り組んだかを思い出したくはありません。



UMatrix (無制限のマトリックス) 〜2008 -1つのブロックに複数の配列要素を格納する一連のメモリブロックからの動的配列。 1つのメモリブロック内のすべての要素を組み合わせることができます。 ここでは、要素のブロックにすぐにメモリを割り当てるというアイデアが実現され、メモリ機能の作業が削減されました。 ビットマスクは、空きアイテム/占有アイテムを決定するために使用されます。 これらのアイデアは、次の配列オプションで使用されます。 テンプレートはまだ私たちの方法ではありませんが、手でコピーすることは非常に難しいため、配列コードジェネレーターが作成されました。



IMatrix (理想的なマトリックス) 〜2009 -ベクトル、1つのメモリブロック内の配列全体。十分なスペースがない場合、より大きなメモリブロックに移動します。 その後、ほとんど使用されず、実際には使用されないことが判明しました。



OMatrix (オブジェクトマトリックス) 〜2010 -UMatrixは一般的なアイデアを繰り返しますが、最初のアイデアがオブジェクトのチェーンである場合、分離のアイデアはここにあります。 ここでは、UMatrixとは異なり、空きオブジェクトのリストとそれらのパスが実装されています。 このクラスはメモリアロケータとして使用され、変数のメモリをすばやく取得/解放できます。

行列が終わり、シートが始まりました。 また、コードジェネレーターは廃止され、テンプレートの使用が許可されました。



MList (マイリスト) 〜2013 -クラスは自動的にユーザークラスを独自にラップし、前の要素と次の要素へのポインターを追加します。



IList (理想的なリスト) 〜2014 -コードジェネレーターをテンプレートで置き換えたIMatrix、同じベクトル。



OList (オブジェクトリスト) 〜2015 -同様に、OMatrixはテンプレート用に書き直されました。



UList (無制限リスト) 〜2015 -置換UMatrix、テンプレート、美しく論理的なコード。



AList (自動リスト)2015 -標準のnew / free、UList、HLString、OListから独自の書き込み機能まで、一連のメモリアロケータを備えた動的配列。



TrieList 2016 -AListに基づいたクイック検索のためのTrieツリーの実装。



残念ながら、配列はパターンで次第に大きくなりすぎています;一方では、これは開発を単純化し、他方では、タスクの理解と変更を複雑にします。



ライブラリの使用



最も簡単な例は、空のプロジェクトを作成し、内容を含む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ファイルを追加する場合、#define USEMSV_GENERALCPP行を削除して、#include ... msvcore.cppまで同じコードを使用する必要があります。 msvcore.cppが接続される前にそれらを指定することにより、追加のライブラリ拡張機能を接続することもできます。たとえば、#define USEMSV_OLISTを使用すると、OList配列を使用できます。 拡張機能のリストはmsvcore.cppで見ることができます



ライブラリのデフォルトでは:





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

バイナリデータ形式の実装、バイナリjsonを備えたCjxContクラス。



#define USEMSV_MLIST、USEMSV_ILIST、USEMSV_OLIST、USEMSV_ALIST、USEMSV_TRIELIST

動的配列の対応するクラスを接続します:MList、IList、OList、AList、TrieList。



#define USEMSV_AMF

AMF形式を変換/解析するためのamfeおよびamfdクラス。



#define USEMSV_PCRE

pcre2正規表現ライブラリを接続します。



#define USEMSV_CONSOLE

他のプロセスを開始するPipeLineおよびPipeLine2クラス。



#define USEMSV_MWND

ウィンドウ、グラフィック、画像を操作するためのほぼ別個のライブラリ。 ライブラリをサポートするすべてのプラットフォームでグラフィックスを操作できます。 プラットフォームに依存しないプリミティブ描画関数が含まれています。 個別に説明する価値があります。 画像形式のエンコード/デコードにCxImageライブラリを使用します。



#define USEMSV_CONSOLELINE

コンソールを操作するための一連のクラス。



#define USEMSV_OPENSSL

opensslおよび暗号化を操作するための関数とクラス。 SSL接続を設定/受信し、それらを操作するためのMySSLクラス。 関数:RsaCreateKeys()-2つの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-MSLバージョン4。 擬似コードを生成せずに、テキストコマンドを実行します。 2013年10月の約1週間に書かれました。また、個別に説明する価値もあります。



#define USEMSV_MSL_FV

Msl Fiveは言語の5番目のバージョンです。 コードバイトの生成とその他の利点。 2015年9月に開発されました。



#define USEMSV_HTTP

HTTP要求を処理するためのクラスと関数。 GetHttpおよびGetHttp2クラス。 openssl関数を接続すると、httpsリクエストがサポートされます。 HTTPヘッダーを操作するためのIHeaderクラス。 Cookieを操作するためのMCookieクラス。



#define USEMSV_CONFLINE

構成ファイルを操作するためのConfLineOptionsクラス。



#define USEMSV_NESTAPI、USEMSV_NESTAPI2

NestApiプロトコルのサーバー側のクラスと関数。



#define USEMSV_STORMSERVER

サーバープラットフォーム。これについては、別の投稿を書きたいと思います。 約10年間、私は良いサーバーを作成しようとしましたが、ついに成功しました。 ほぼ完璧なソリューション。



#define USEMSV_LIGHTSERVER

LightServerクラスは、独自のハンドラーを作成できるシンプルで簡単なサーバーです。 LightServerHttpクラスは、テストページを返す単純なhttpsサーバーです。



#define USEMSV_TGBOTS

TgBotクラスとTgBotsクラスは、電報ボットを実装しています。



#define USEMSV_ANDROID

Android用にコンパイルする際の作業を簡素化する関数とクラス。



#define USEMSV_TRAFFIX

トラフィックを聞くためのクラス。



#define USEMSV_BUFECHO

コンソールオプションを変更するための関数。


おわりに



私にちなんで名付けられたこのバイクに興味を持っていただければ幸いです。 私の意見では、文字列、配列、opensslのラッパーが書かれている、msl、または電報でボットを作成するためのクラスから始まる非常に興味深いものがあり、興味があるかもしれません、そして最後に、stormserverはさまざまなサーバーを作成するためのプラットフォームです。 後者については、単純なエコーサーバーから複雑なhttpやプロキシまで、サーバーの開発に関する別の記事を作成します。



私が言ったように、ライブラリは開発されたプログラムにかなり偏っています。 実践が示すように、それ自体は特定のタスクなしで開発することは困難です。



このライブラリは、プログラミングの方法を学び、コードが最初から最後まで何をするかを理解するために作成しました。 そして、私は言わなければならない、進歩はあるが、それでも仕事と仕事。



将来の計画では、もう一度、ゼロから書き直し、古いコードを完全に取り除き、整理します。 そして、最終的にドキュメントを書くかもしれません。 また、現在の、および新しい動的配列の代わりとして、文字列の新しいオプションの実装を追加する計画。



ライブラリコードといくつかのプロジェクト



All Articles