ぬの部屋(仮)
nu-no-he-ya
  •   12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • CLionでGithub Copilotを使う

    CLionでGithub Copilotを使用する。

    設定から[プラグイン] → [Marketplace]で Github Copilot を検索。

    サードパーティプラグインに関する通知 が出るが、Github公式のもなので安心して同意する。

    IDEを再起動する。

    再起動後、右下のアイコンをクリックしてLogin to Githubを選択。選択できないなら一度ログアウトする。

    Copy and OpenでGithubへ入って完了。動かないようなら一度CLionを再起動する。

    C++にLuaを組み込む(3)テーブルの値の取得とスタックの状態の確認

    Luaに構造体はないがテーブルがあり構造体と同じような書き方ができる。

    LuaとC++の通信はLuaのスタックを介して行われるため、Luaのスタックの挙動を知っておく必要がある。

    基本的な使い方

    1.lua_getglobalでスクリプト内のテーブルへの参照をスタックへPush

    2.lua_getfieldでテーブルへの参照から指定したキーの値をスタックへPush

    3.lua_tostringでスタックの先頭の値を読み込んで表示

    4.スタックをPopして次の処理に備える

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    // Luaスクリプト
    static const char* script = R"(
    
    MyLuaTable ={
       val_a = "VAL_A",
       val_b = "VAL_B",
       val_c = "VAL_C",
       val_d = "VAL_D",
    }
    
    )";
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // 文字列で与えてスクリプトを実行する
        luaL_dostring(luas, script);
    
        // テーブルへアクセス
        lua_getglobal(luas, "MyLuaTable");// MyLuaTableへの参照をスタックの一番上にPush
    
        {
            // lua_getfieldでテーブルから値を取得
            // 第一引数 ... lua_State
            // 第二引数 ... テーブルのスタック上の位置を現在のスタック位置からの差で表す
            // 第三引数 ... テーブルのキー
            /*
            * スタックの状態
            *  4 □
            *  3 □
            *  2 □ 現在位置==2。   現在位置-1 == 1。従ってlua_getfieldは'1'で参照されているテーブルから'val_a'を取り出し、ここへPushする 
            *  1 ■ MyLuaTableへの参照 lua_getglobalによりPushされている
            */
            lua_getfield(luas, -1, "val_a"); // val_aの値(現在位置からMyLuaTableまでの距離は-1)をスタックの一番上にPush
            const char* value = lua_tostring(luas, -1); // スタックの一番上の値を取得
            printf("value: %s\n", value);
            lua_pop(luas, 1/*要素を一つPOP*/);  // スタックの一番上の要素をPop。これで現在のスタック位置が2に戻る
        }
    

        {
            lua_getfield(luas, -1, "val_b"); // val_bの値(MyLuaTableまでの距離は-1)をスタックの一番上にPush
            const char* value = lua_tostring(luas, -1); // スタックの一番上の値を取得
            printf("value: %s\n", value);
            lua_pop(luas, 1/*要素を一つPOP*/);  // スタックの一番上の要素をPop
        }
    

    // Luaの終了。全てのメモリ解放 lua_close(luas); }
    value: VAL_A
    value: VAL_B

    スタックの状態確認

    lua_getglobalとlua_getfieldの挙動がわからなかったので、スタックの状態を確認する。

    以下のコードはスクリプトで定義されたテーブルへアクセスするために、各値をひたすらスタックへ積んでいく。

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    
    // Luaスクリプト
    static const char* script = R"(
    
    MyLuaTable_1 ={
       val_1_a = "VAL_1_A",
       val_1_b = "VAL_1_B",
       val_1_c = "VAL_1_C",
       val_1_d = "VAL_1_D",
    }
    
    MyLuaTable_2 ={
       val_2_a = "VAL_2_A",
       val_2_b = "VAL_2_B",
       val_2_c = "VAL_2_C",
       val_2_d = "VAL_2_D",
    }
    
    )";
    
    
    // Lua スタックの内容を表示
    void print_stack(lua_State* luas) {
    
        // スタックのトップの位置を取得
        int top = lua_gettop(luas);
    
        // 全てのスタックの内容を表示
        // Luaのスタックは1から始まる
        for (int pos = 1; pos <= top; pos++) {
            
            int type = lua_type(luas, pos);
    
            printf("%d: ", pos);
            switch (type) {
            case LUA_TSTRING:
                printf("'%s'", lua_tostring(luas, pos));
                break;
            case LUA_TBOOLEAN:
                printf(lua_toboolean(luas, pos) ? "true" : "false");
                break;
            case LUA_TNUMBER:
                printf("%g", lua_tonumber(luas, pos));
                break;
            case LUA_TNIL:
                printf("nil");
                break;
            case LUA_TTABLE:
                printf("table Reference");
                break;
            case LUA_TFUNCTION:
                printf("function");
                break;
            case LUA_TUSERDATA:
                printf("userdata");
                break;
            case LUA_TTHREAD:
                printf("thread");
                break;
            case LUA_TLIGHTUSERDATA:
                printf("light userdata");
                break;
            default:
                printf("unknown");
                break;
            }
            printf("\n");
        }
    }
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // 文字列で与えてスクリプトを実行する
        luaL_dostring(luas, script);
    
        {
            // テーブルへアクセス
            lua_getglobal(luas, "MyLuaTable_1");// MyLuaTable_1への参照をスタックの一番上にPush
            lua_getglobal(luas, "MyLuaTable_2");// MyLuaTable_2への参照をスタックの一番上にPush
    
            lua_getfield(luas, -1, "val_2_a"); // val_2_aの値(MyLuaTable_2までの距離は-1)をスタックの一番上にPush
            lua_getfield(luas, -2, "val_2_b"); // val_2_bの値(MyLuaTable_2までの距離は-2)をスタックの一番上にPush
            lua_getfield(luas, -3, "val_2_c"); // val_2_aの値(MyLuaTable_2までの距離は-3)をスタックの一番上にPush
            lua_getfield(luas, -4, "val_2_d"); // val_2_bの値(MyLuaTable_2までの距離は-4)をスタックの一番上にPush
            //        [現在位置-5] にはMyLuaTable_2への参照が積まれている
            lua_getfield(luas, -6, "val_1_a"); // val_1_aの値(MyLuaTable_1までの距離は-6)をスタックの一番上にPush
            lua_getfield(luas, -7, "val_1_b"); // val_1_bの値(MyLuaTable_1までの距離は-7)をスタックの一番上にPush
            lua_getfield(luas, -8, "val_1_c"); // val_1_cの値(MyLuaTable_1までの距離は-8)をスタックの一番上にPush
            lua_getfield(luas, -9, "val_1_d"); // val_1_dの値(MyLuaTable_1までの距離は-9)をスタックの一番上にPush
    
        }
        print_stack(luas); // スタックの内容を表示
    
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    1: table Reference
    2: table Reference
    3: 'VAL_2_A'
    4: 'VAL_2_B'
    5: 'VAL_2_C'
    6: 'VAL_2_D'
    7: 'VAL_1_A'
    8: 'VAL_1_B'
    9: 'VAL_1_C'
    10: 'VAL_1_D'

    スタックの値へアクセス

    lua_tostringの第二引数には、スタックの先頭からの距離を指定する。-1は先頭に積まれている値を指す。例えば-4を指定すれば、先頭から4つ目の値へアクセスする。


        // テーブルへアクセス
        lua_getglobal(luas, "MyLuaTable_1");// MyLuaTable_1への参照をスタックの一番上にPush
        lua_getglobal(luas, "MyLuaTable_2");// MyLuaTable_2への参照をスタックの一番上にPush
    
        lua_getfield(luas, -1, "val_2_a"); // val_2_aの値(MyLuaTable_2までの距離は-1)をスタックの一番上にPush
        lua_getfield(luas, -2, "val_2_b"); // val_2_bの値(MyLuaTable_2までの距離は-2)をスタックの一番上にPush
        lua_getfield(luas, -3, "val_2_c"); // val_2_aの値(MyLuaTable_2までの距離は-3)をスタックの一番上にPush
        lua_getfield(luas, -4, "val_2_d"); // val_2_bの値(MyLuaTable_2までの距離は-4)をスタックの一番上にPush
        //        [現在位置-5] にはMyLuaTable_2への参照が積まれている
        lua_getfield(luas, -6, "val_1_a"); // val_1_aの値(MyLuaTable_1までの距離は-6)をスタックの一番上にPush
        lua_getfield(luas, -7, "val_1_b"); // val_1_bの値(MyLuaTable_1までの距離は-7)をスタックの一番上にPush
        lua_getfield(luas, -8, "val_1_c"); // val_1_cの値(MyLuaTable_1までの距離は-8)をスタックの一番上にPush
        lua_getfield(luas, -9, "val_1_d"); // val_1_dの値(MyLuaTable_1までの距離は-9)をスタックの一番上にPush
    
    ///////////////////////////////////////// // 現在位置から -4 の位置にある値を取得 const char* value = lua_tostring(luas, -4); // val_1_a の値を取得 printf("value: %s\n", value);
    value: VAL_1_A

    C++にLuaを組み込む(2)C++とLuaで変数の受け渡しを行う

    LuaとC/C++のデータの受け渡しはLuaのスタックを介して行う。

    例1 Lua側で ... でスタックから値取り出し

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    
    int main()
    {
    
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
    // lua_pcallで呼び出す。 スタックに積まれた変数を取り出すには ... を使用 luaL_loadstring(luas, R"(
            local val1,val2 = ...;
            print("Received value:", val1,val2);
    
    )");
    
    lua_pushinteger(luas, 10); // 値をスタックに積む lua_pushstring(luas, u8"Hello World"); // 値をスタックに積む。文字列はUTF-8で渡す
    lua_pcall(luas, 2, 0, 0); // Luaの終了。全てのメモリ解放 lua_close(luas); }
    Received value: 10 Hello World

    ※このコードを実行するとセキュリティソフトにウィルス認定されるんだが、ヒューリスティックスキャンが誤爆でもしているのか?

    例2 グローバル変数へ値を設定

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    
    int main()
    {
    
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // Luaスクリプト
        // luaL_loadstringによりコンパイルされる
        int load_status = luaL_loadstring(luas, R"(
    
          function myfunc()
            print(my_string);
            print(my_int);
          end
    
    )");
    
        if (load_status == LUA_OK) {
            // Luaスクリプトを実行
            // スクリプトを実行しているだけなので関数を実行しているわけではない
            // このスクリプト実行で myfunc()が定義される。
            lua_pcall(luas, 0, 0, 0);
        }
    
        lua_pushinteger(luas, 10);           // 値をPushする
        lua_setglobal(luas, "my_int");       // グローバル変数を定義し、値をセット
    
        lua_pushstring(luas, "Hello World"); // 値をPushする
        lua_setglobal(luas, "my_string");    // グローバル変数を定義し、値をセット
    
        // 一回目の lua_pcall で定義した myfunc() をスタックへPushする
        lua_getglobal(luas, "myfunc");    
        lua_pcall(luas, 0, 0, 0);// myfunc呼び出し
    
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    Hello World
    10

    例3 グローバル変数から値を取得

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    
    int main()
    {
    
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // lua_pcallでコンパイル
        luaL_loadstring(luas, R"(
    
    global_value = 105
    
    )");
    
        // Luaスクリプトを実行
        lua_pcall(luas, 0, 0, 0);
    
        lua_getglobal(luas, "global_value");
        int gval = lua_tointeger(luas, -1);
        printf("global_value = %d\n", gval);
    
    
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    global_value = 105

    C++にLuaを組み込む(1)C++からスクリプト実行/スクリプトからC++の関数実行

    LuaはC言語に組み込みやすい言語。

    Windows版をmakeするのは面倒なので、ビルド済みバイナリをダウンロードする。

    以下URLへ行き、Historyから Release 1とついているものをダウンロードする。

    https://luabinaries.sourceforge.net

    例1 与えた文字列をスクリプトとして実行

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
    // Luaスクリプト const char* script = R"(
    for i = 1,5 do
      print(i)
    end
    )";
    
        // 文字列で与えてスクリプトを実行する
        luaL_dostring(luas, script);
        
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    1
    2
    3
    4
    5

    例2 ファイル名を与えて実行

    myscript.lua

    for i = 1,5 do
      print(i)
    end
    

    呼び出し側

    #include <iostream>
    
    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // myscript.luaを実行する
        // luaL_dofileでもいい。luaL_dofileはマクロ。
        // luaL_dofile(luas, "myscript.lua");
    
        luaL_loadfile(luas, "myscript.lua");// スクリプトファイル読み込み
        lua_pcall(luas, 0, LUA_MULTRET, 0);// スクリプト実行
        
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    1
    2
    3
    4
    5

    例3 C++からLuaの関数を呼び出す

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        luaL_dostring(luas,
    R"(
    
    function calc(x, y)
      return 
        x + y,
        x - y,
        x * y,
        x / y
    end
    
    )"
    );
    
        // Luaの関数を呼び出す
        // 引数はスタックにプッシュして渡す
        /////////////////////////////////////////////
        lua_getglobal(luas, "calc"); // add 関数をスタックにプッシュ
        lua_pushnumber(luas, 3); // 第一引数 x に 3 をプッシュ
        lua_pushnumber(luas, 7); // 第二引数 y に 7 をプッシュ
        /////////////////////////////////////////////
        // 関数呼び出し
        int ret = lua_pcall(
            luas,
            2, // 引数の数
            4, // 戻り値の数
            0  // エラーハンドラのインデックス
        );
        /////////////////////////////////////////////
        // エラーチェック
        if (ret != LUA_OK) {
            const char* err = lua_tostring(luas, -1);
            printf("error: %s\n", err);
            return -1;
        }
        /////////////////////////////////////////////
        // 戻り値を取得
        int add = (int)lua_tonumber(luas, -4);// 戻り値1
        int sub = (int)lua_tonumber(luas, -3);// 戻り値
        double mul = (double)lua_tonumber(luas, -2);// 戻り値
        double div = (double)lua_tonumber(luas, -1);// 戻り値
        printf("add = %d\n", add);
        printf("sub = %d\n", sub);
        printf("mul = %f\n", mul);
        printf("div = %f\n", div);
        /////////////////////////////////////////////
        
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    add = 10
    sub = -4
    mul = 21.000000
    div = 0.428571

    例4 LuaからC++の関数を呼び出す

    #include <lua.hpp>
    
    // lua54.dllが必要
    #pragma comment(lib, "lua54.lib")
    
    
    int ccalc(lua_State* L) {
        double a = luaL_checknumber(L, 1); // 1番目の引数を取得
        double b = luaL_checknumber(L, 2); // 2番目の引数を取得
    
        // 結果をスタックにプッシュ
        lua_pushnumber(L, a + b);
        lua_pushnumber(L, a - b);
        lua_pushnumber(L, a * b);
        lua_pushnumber(L, a / b);
        return 4; // 戻り値の数を返す
    }
    
    int main()
    {
        lua_State* luas = luaL_newstate();
    
        // Luaの標準ライブラリを読み込む
        luaL_openlibs(luas);
    
        // C++の関数をLuaに登録
        lua_register(luas, "ccalc", ccalc);
    
        // LuaからC++の関数を呼び出す
        luaL_dostring(luas,
    R"(
    
    add,sub,mul,div = ccalc(3, 7)
    print("add",add)
    print("sub",sub)
    print("sub",mul)
    print("div",div)
    
    )"
    );
    
        // Luaの終了。全てのメモリ解放
        lua_close(luas);
    
    }
    
    add 10.0
    sub -4.0
    sub 21.0
    div 0.42857142857143

    C++CLIでParallel::For (改)

    過去のParallel::Forの記事がかなりわかりにくかったので再度書く。過去記事:

    C++CLIでParallel::For

    以下サンプル

    C++(普通コード)

    int i;
    int c1[100];
    
    for (i = 0; i < 100; i ++) {
      c1[i] = i;
    }
    

    C++CLI (Parallel::For)

    #include "pch.h"
    
    using namespace System;
     
    // Parallel::Forでデータを操作する関数を含んだクラス
    ref struct LoopObject {
        int *_array;
    public:
        LoopObject(int* data) {
            _array = data;
        }
    
        // データを操作する関数
        // Parallel::Forの場合は、intの引数一つである必要がある
        // 引数 i ループカウンタ for(int i = 0;i<SIZE;i++){  function(i); } のような感じ
    void function(int i) { // データを操作 _array[i] = i; } };
    int main(array<System::String^>^ args)
    {
        // データ
        const int SIZE = 100;
        int c1[SIZE];
    
        // Parallel::Forでデータを操作する関数を含んだクラスのインスタンスを生成
        LoopObject^ forInstance = gcnew LoopObject(c1);// コンストラクタにデータを渡す
    
        // forの範囲を指定
        int BEGIN = 0;
        int END = SIZE;
    
        // 並列処理実行 For( 開始Index , 終了Index , 一回分の処理を行う関数オブジェクト )
        System::Threading::Tasks::Parallel::For(
            BEGIN,
            END,
            gcnew Action<int>(forInstance, &LoopObject::function)
        );
    
        // 結果を表示
        for (int i = 0; i < SIZE; i++) {
            System::Console::WriteLine(
                System::String::Format("mydata[{0}] = {1}", i, c1[i]));
        }
    
        Console::ReadLine();
    
        return 0;
    }
    

    Action<int>のintはLoopObject::functionの引数がintなので、ループカウンタを与える関数に合わせているのだが、問題はParallel::Forがintしか受け付けていないので、実質Action<int>以外に選択肢がない(Action<size_t>などやってもParallel::Forでビルドエラーになる)。

    C++で構造だけまねた例

    要は「関数オブジェクトを並列で呼び出す関数」がParallel::Forで、Actionのインスタンスが関数オブジェクトになる。C++でそれっぽいコードを書くと以下になる。

    std::sort(begin,end,[](...){...});とやるときと考え方は同じ。

    #include <functional>
    
    struct LoopObject {
        int* _array;
    public:
        LoopObject(int* data) {
            _array = data;
        }
    
        // データを操作する関数
        // Parallel::Forの場合は、intの引数一つである必要がある
        // 引数 i ループカウンタ for(int i = 0;i<SIZE;i++){  function(i); } のような感じ
        void function(int i) {
    
            // データを操作
            _array[i] = i;
    
        }
    };
    
    namespace Parallel
    {
        void For(int start, int end, LoopObject* action)
        {
            // 本来はここは並列処理で呼び出すが
            // 今回はシングルスレッドで実行する
            for (int i = start; i < end; i++)
            {
                action->function(i);
            }
        }
    }
    
    int main()
    {
        int c1[100];
    
        auto action = new LoopObject(c1);
    
        Parallel::For(0, 100, action);
    
    
        // 結果の表示
        for (int i = 0; i < 100; i++)
        {
            printf("%d\n", c1[i]);
        }
    
    
    }
    

    FreeType2でBold、Italicの文字を描画(2)

    Bold、Italicなどが別々のファイルに分かれている場合、各ファイルのfamily_nameがフォントの種類を特定する指標となり、同じフォントのfamily_nameは共通しているので、family_nameごとに纏めた辞書を作れば、特定のfamillyに対してスタイルを選択することができる。

    #include <iostream>
    
    #include <vector>
    #include <fstream>
    #include <filesystem>
    #include <unordered_map>
    
    #include <ft2build.h>
    #include FT_FREETYPE_H
    
    #pragma warning(disable:4996)
    
    #ifdef _DEBUG
    #pragma comment(lib,"freetyped.lib")
    #else
    #pragma comment(lib,"freetype.lib")
    #endif
    
    
    //! @brief PBM(1byte,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む
    void pbmP1_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII
    
        FILE* fp = fopen(fname, "wb");
        fprintf(fp, "P1\n%d\n%d\n", width, height);
    
        size_t k = 0;
        for (size_t i = 0; i < (size_t)height; i++) {
            for (size_t j = 0; j < (size_t)width; j++) {
                fprintf(fp, "%d ", p[k] ? 0 : 1);
                k++;
            }
            fprintf(fp, "\n");
        }
    
        fclose(fp);
    }
    
    
    bool render(FT_Face face, FT_ULong character) {
    
        //文字コード指定
        FT_Error error = FT_Select_Charmap(
            face,               // target face object
            FT_ENCODING_UNICODE // エンコード指定
        );
    
    
        if (error == FT_Err_Unknown_File_Format)
            return false;
        else if (error)
            return false;
    
        //この二つの値でフォントサイズ調整
        FT_F26Dot6 fontsize = 16 * 64*2;
        FT_UInt CHAR_RESOLUTION = 300;
        error = FT_Set_Char_Size(
            face,                // handle to face object
            0,                   // char_width in 1/64th of points
            fontsize,            // char_height in 1/64th of points
            CHAR_RESOLUTION,     // horizontal device resolution
            CHAR_RESOLUTION);    // vertical device resolution
    
    
        FT_UInt char_index = FT_Get_Char_Index(face, character);
    
        // グリフ(字の形状)読込
        error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER);
        if (error)
            return -1; // ignore errors
    
        // 文字を画像化
        FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
    
        int Width = face->glyph->bitmap.width;
        int Height = face->glyph->bitmap.rows;
    
    
        char filename[1024];
        sprintf(filename, "C:\\test\\freetypetest_%s.pbm", face->style_name);
    
        pbmP1_Write(// ファイル保存
            filename,
            Width,
            Height,
            face->glyph->bitmap.buffer
        );
    
    }
    

    // filesystemでフォントファイル名一覧を取得する
    std::vector<std::string> getFontFileList(const std::string& fontdir) {
        namespace fs = std::filesystem;
    
        std::vector<std::string> fontList;
    
        if (!fs::exists(fontdir) || !fs::is_directory(fontdir)) {
            std::cerr << "Directory does not exist: " << fontdir << std::endl;
            return fontList;
        }
    
        // Iterate through the directory
        for (const auto& entry : fs::directory_iterator(fontdir)) {
            if (entry.is_regular_file()) {
                auto path = entry.path();
                fontList.push_back(path.string());
            }
        }
    
        return fontList;
    }
    

    // フォントファイルからフォントを取得し、フォントファミリでグループ化する
    std::unordered_map<std::string, std::vector<std::pair<std::string, FT_Face>> > getFonts(FT_Library library,const std::vector<std::string>& flist) {
    
        std::unordered_map<
            std::string, 
            std::vector< std::pair<std::string,FT_Face> > > fontmap;
    
        for (const auto& file : flist) {
    
            FT_Face face;      // handle to face object
    
            // フォントファイル読み込み
            FT_Error error = FT_New_Face(
                library,
                file.c_str(),
                0,
                &face
            );
            if(error)
                continue;
    
            fontmap[face->family_name].push_back({ file,face });// ファミリ名をキーとしてフェイスを保存
    
        }
    
        return fontmap;
    
    }
    
    int main()
    {
    
        FT_Library library; // handle to library
        FT_Error error;
    
        error = FT_Init_FreeType(&library);
        if (error)
            return -1;
    
        std::vector<std::string> flist = getFontFileList("C:\\Windows\\Fonts\\");
    
        // フォントファミリでグループ化したフォントリストを取得
        auto famillies = getFonts(library, flist);
    
        // arialフォントのファミリ名で取得
        const auto& arial = famillies["Arial"];
        for( const auto& [file,face] : arial){
            std::cout << face->style_name << std::endl;
            render(face, wchar_t(L'A'));
        }
    
        // フォント解放
        for (auto& familly : famillies) {
            for (std::pair<std::string,FT_Face>& tf : familly.second) {
                FT_Face face = tf.second;
                FT_Done_Face(face);
            }
        }
    
    
        FT_Done_FreeType(library);
    }
    

    出力

    Regular
    Bold
    Bold Italic
    Italic
    Narrow
    Narrow Bold
    Narrow Bold Italic
    Narrow Italic
    Black

    FreeType2でBold、Italicの文字を描画(1)

    同じフォントの太字、斜体でも、別のファイルに分かれていることがかなりある。フォントフォルダから別フォルダに移すとファイル名がわかる。

    #include <iostream>
    
    #include <vector>
    #include <fstream>
    
    
    #include <ft2build.h>
    #include FT_FREETYPE_H
    
    #pragma warning(disable:4996)
    
    #ifdef _DEBUG
    #pragma comment(lib,"freetyped.lib")
    #else
    #pragma comment(lib,"freetype.lib")
    #endif
    
    
    //! @brief PBM(1byte,テキスト)を書き込む
    //! @param [in] fname ファイル名
    //! @param [in] width 画像の幅
    //! @param [in] height 画像の高さ
    //! @param [in] p 画像のメモリへのアドレス
    //! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む
    void pbmP1_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII
    
        FILE* fp = fopen(fname, "wb");
        fprintf(fp, "P1\n%d\n%d\n", width, height);
    
        size_t k = 0;
        for (size_t i = 0; i < (size_t)height; i++) {
            for (size_t j = 0; j < (size_t)width; j++) {
                fprintf(fp, "%d ", p[k] ? 0 : 1);
                k++;
            }
            fprintf(fp, "\n");
        }
    
        fclose(fp);
    }
    
    
    bool render(FT_Library library,const std::string fname, FT_ULong character,int face_index) {
    
    
        FT_Face face;      // handle to face object
    
        // フォントファイル読み込み
        FT_Error error = FT_New_Face(
            library,
            fname.c_str(),
            0,
            &face
        );
    
        //文字コード指定
        error = FT_Select_Charmap(
            face,               // target face object
            FT_ENCODING_UNICODE // エンコード指定
        );
    
    
        if (error == FT_Err_Unknown_File_Format)
            return false;
        else if (error)
            return false;
    
        //この二つの値でフォントサイズ調整
        FT_F26Dot6 fontsize = 16 * 64;
        FT_UInt CHAR_RESOLUTION = 300;
        error = FT_Set_Char_Size(
            face,                // handle to face object
            0,                   // char_width in 1/64th of points
            fontsize,            // char_height in 1/64th of points
            CHAR_RESOLUTION,     // horizontal device resolution
            CHAR_RESOLUTION);    // vertical device resolution
    
    
        FT_UInt char_index = FT_Get_Char_Index(face, character);
    
        // グリフ(字の形状)読込
        error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER);
        if (error)
            return -1; // ignore errors
    
        // 文字を画像化
        FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
    
        int Width = face->glyph->bitmap.width;
        int Height = face->glyph->bitmap.rows;
    
    
        char filename[1024];
        sprintf(filename, "C:\\test\\freetypetest_%d.pbm", face_index);
    
        pbmP1_Write(// ファイル保存
            filename,
            Width,
            Height,
            face->glyph->bitmap.buffer
        );
    
        // FreeType2の解放
        FT_Done_Face(face);
    
    
    }
    

    int main()
    {
    
        FT_Library  library; // handle to library
        FT_Error error;
    
        error = FT_Init_FreeType(&library);
        if (error)
            return -1;
    
        // 文字の取得
        FT_ULong character = wchar_t(L'A');
    
        render(library, "C:\\Windows\\Fonts\\arial.ttf", character, 0);    // Regular
        render(library, "C:\\Windows\\Fonts\\ariali.ttf", character,1);    // Italic
        render(library, "C:\\Windows\\Fonts\\arialbd.ttf",character,2);    // Bold
        render(library, "C:\\Windows\\Fonts\\arialnbi.ttf", character, 3); // Bold Italic
    
        FT_Done_FreeType(library);
    }
    

    VC++で選択されている状態で>などを入力すると<>で囲まれてしまう機能の無効化

    症状

    最近のVC++(2022とか)で、文字列を選択した状態で、>を入力すると、選択した内容が <選択範囲> の形で囲まれてしまう。"でも同様のことが起こる。HTMLタグとかtemplate引数とかには便利かもしれないが、選択中に文字を入力したら置換してほしい。特に、時々やるのが、メンバ関数を間違ったときに書き換えようとして状況が悪化するため、この挙動に年単位で悩まされていた。

    設定

    テキストエディター → C/C++ → 詳細設定 → 自動サラウンドモード

    「自動サラウンドモード」を「なし」に設定する。

    なお

    メンバの修正は、VC++では、ctrl+spaceでメンバの候補リストを出すことができる。

    単語だけ選択→Backspace→ctrl+spaceをするのが正当な修正方法。

    二つの配列からなる値をクイックソート

    前回C++で実装したクイックソートで、二つの配列を同時にクイックソートする。

    #include <iostream>
    #include <vector>
    
    
    // 配列の分割を行う関数(ピボットの位置を変更しない)
    template<typename Container, class QElem>
    size_t partition(Container& arr, size_t low, size_t high) {
        size_t mid = low + (high - low) / 2; // 中央の要素をピボットとして選択
        QElem pivot(arr, mid);               // ピボットの値を取得
    
        size_t i = low;
        size_t j = high;
    
        while (true) {
            // ピボットより小さい要素を左側に移動
            while (QElem::Lesser(arr,i,pivot) ){
                i++;
            }
    
            // ピボットより大きい要素を右側に移動
            while (QElem::Greater(arr,j,pivot) ) {
                j--;
            }
    
            // 左右の走査が交差した場合に分割終了
            if (i >= j) {
                return j;
            }
    
            // 交差していない場合、要素を交換
            QElem::Swap(arr, i, j);
            i++;
            j--;
        }
    }
    

    // クイックソートを行う関数
    template<typename Container, class QElem>
    void quick_sort(Container& arr, size_t low, size_t high) {
    
        if (low < high) {
            size_t pi = partition<Container,QElem>(arr, low, high);
    
            if (pi > low)
                quick_sort<Container, QElem>(arr, low, pi);// ピボットの左側をソート
            quick_sort<Container, QElem>(arr, pi + 1, high);// ピボットの右側をソート
        }
    }
    

    // 二つの配列を一つにまとめて渡すための構造体
    struct
    Vector2Reference { std::vector<float>& value; std::vector<std::string>& label; Vector2Reference(std::vector<float>& v, std::vector<std::string>& l) : value(v), label(l) {} size_t size() const { return value.size(); } };

    struct QsortElement {
        float value;
    
        // Pivotの値を保存するためのオブジェクト用のコンストラクタ
        QsortElement(const Vector2Reference& arr, size_t index) {
            value = arr.value[index];
        }
    
        // 要素の交換関数
        static void Swap(Vector2Reference& arr, size_t i, size_t j) {
            std::swap(arr.value[i], arr.value[j]);
            std::swap(arr.label[i], arr.label[j]);
        }
    
        // 比較関数
        static bool Lesser(Vector2Reference& arr, size_t i, const QsortElement& qe) {
            return arr.value[i] < qe.value;
    	}
        // 比較関数
        static bool Greater(Vector2Reference& arr, size_t i, const QsortElement& qe) {
            return arr.value[i] > qe.value;
        }
    };
    
    int main() {
    
        std::vector<float> value;
        std::vector<std::string> label;
        value.push_back(5.0f);    label.push_back("e");
        value.push_back(1.0f);    label.push_back("a");
        value.push_back(3.0f);    label.push_back("c");
        value.push_back(4.0f);    label.push_back("d");
        value.push_back(2.0f);    label.push_back("b");
    
    
        Vector2Reference arr2(value, label);
    
        std::cout << "ソート前の配列: " << std::endl;
        for (size_t i = 0; i < arr2.size(); i++) {
            std::cout << arr2.value[i] << " " << arr2.label[i] << std::endl;
        }
    
        quick_sort< Vector2Reference, QsortElement>(arr2, (size_t)0, arr2.size()-1);
    
        std::cout << "ソート後の配列: " << std::endl;
        for (size_t i = 0; i < arr2.size(); i++) {
            std::cout << arr2.value[i] << " " << arr2.label[i] << std::endl;
        }
    
    
        return 0;
    }
    
    ソート前の配列:
    5 e
    1 a
    3 c
    4 d
    2 b
    ソート後の配列:
    1 a
    2 b
    3 c
    4 d
    5 e

    C++でクイックソート(テンプレート使用)

    C++でクイックソートを実装する。ただし、諸事情によりピボット保存、比較演算、スワップ関数を外部で実装し、テンプレートで渡す形式にする(QElem)。

    #include <iostream>
    #include <vector>
    
    
    // 配列の分割を行う関数
    template<typename Container, class QElem>
    size_t partition(Container& arr, size_t low, size_t high) {
        size_t mid = low + (high - low) / 2; // 中央の要素をピボットとして選択
        QElem pivot(arr, mid);               // ピボットの値を取得
    
        size_t i = low;
        size_t j = high;
    
        while (true) {
            // ピボットより小さい要素を左側に移動
            while (QElem::Lesser(arr,i,pivot) ){
                i++;
            }
    
            // ピボットより大きい要素を右側に移動
            while (QElem::Greater(arr,j,pivot) ) {
                j--;
            }
    
            // 左右の走査が交差した場合に分割終了
            if (i >= j) {
                return j;
            }
    
            // 交差していない場合、要素を交換
            QElem::Swap(arr, i, j);
            i++;
            j--;
        }
    }
    

    // クイックソートを行う関数
    template<typename Container, class QElem>
    void quick_sort(Container& arr, size_t low, size_t high) {
    
        if (low < high) {
            size_t pi = partition<Container,QElem>(arr, low, high);
    
            if (pi > low)
                quick_sort<Container, QElem>(arr, low, pi);// ピボットの左側をソート
            quick_sort<Container, QElem>(arr, pi + 1, high);// ピボットの右側をソート
        }
    }
    

    struct QsortElement {
        float value;
    
        // Pivotの値を保存するためのオブジェクト用のコンストラクタ
        QsortElement(const std::vector<float>& arr, size_t index) {
            value = arr[index];
        }
    
        // 要素の交換関数
        static void Swap(std::vector<float>& arr, size_t i, size_t j) {
            std::swap(arr[i], arr[j]);
        }
    
        // 比較関数
        static bool Lesser(std::vector<float>& arr, size_t i, const QsortElement& qe) {
            return arr[i] < qe.value;
        }
        // 比較関数
        static bool Greater(std::vector<float>& arr, size_t i, const QsortElement& qe) {
            return arr[i] > qe.value;
        }
    };
    
    int main() {
    
        std::vector<float> arr = {5.2f, 1.8f, 3.2f, 4.3f, 2.7f};
    
        std::cout << "ソート前の配列: " << std::endl;
        for (size_t i = 0; i < arr.size(); i++) {
            std::cout << arr[i] << " " << std::endl;
        }
    
        quick_sort< std::vector<float>, QsortElement>(arr, (size_t)0, arr.size()-1);
    
        std::cout << "ソート後の配列: " << std::endl;
        for (size_t i = 0; i < arr.size(); i++) {
            std::cout << arr[i] << " " << std::endl;
        }
    
    
        return 0;
    }
    
    ソート前の配列:
    5.2
    1.8
    3.2
    4.3
    2.7
    ソート後の配列:
    1.8
    2.7
    3.2
    4.3
    5.2