Effective C++ 第二章

項目5: 明示的宣言よりも auto を優先する

  • auto で宣言することのメリット
    • 複雑な型宣言の省略
template<typename It>
void f(It b, It e)
{
  while (b != e)
  {
     typename std::iterator_traits<It>::value_type cV = *b;
     // auto cV = *b;
   }
}
  • 未初期化のエラーを防げる
    • auto 宣言した場合には、初期化必須
  • コンパイラにしか分からない型(ラムダ式等)も表現可能
auto deffLess = [](const std::unique_ptr<Widget>& p1, const std::unique_ptr<Widget>& p2) { return *p1 < *p2; }
// C++14
auto deffLess = [](const auto& p1, const auto& p2) { return *p1 < *p2; }
  • C++11 で登場した std::function 型でもラムダ式は表現可能だが、以下の点で auto のほうが有利

  • 型のショートカットによる実行環境依存の問題を回避できる

std::vector<int> v;
unsigned sv = v.size();
// v.size() の戻り値の型は、std::vector<int>::size_type 型は、実行環境によりサイズが異なる
// Windows 32bit では、32bit
// Windows 64bit では、64bit
// 一方 unsigned は どちらも32bit
  • 型宣言のミスによる不要なオブジェクトのコピー及び未定義動作を回避可能
std::unordered_map<std::string, int> m;
// std::pair 型は std::pair<const std::string, int> が正解
// 型の不一致により、一時オブジェクトが生成され、ループ内の最後の処理で破棄される
for(const std::pair<std::string, int> p : m)
{
   ...
}
  • ただし、auto による型宣言にも落とし穴がある
    • 統一初期化子で初期化した変数の型が std::initializer_list になる
    • std::vector 型のコンテナに対して operator を実行すると、std::vector::reference が戻されることによる未定義動作の発生

項目6: auto が期待と異なる型を推論する場面では ETII を用いる

  • std::vector に対する operator はコンテナ要素の参照を返さない
    • C++ ではビットの参照を認めていない
    • std::vector の operator[] は T& を返す関数
    • bool& は返すことができないため、bool& のように振る舞うオブジェクトを返す
    • それが、std::vector::reference
      • これは Proxy Class の一例
        • Proxy Class には使用者にプロキシを意識させるものとそうでないものがある
          • 意識させるもの: スマートポインタ
          • 意識させないもの: std::vector::reference
            • これが auto との相性が悪い (ユーザに意識させないプロキシクラスは、ライフタイムを1文以内と想定している)
            • つまり、ユーザに意識させないプロキシクラスに対する auto 宣言は避けるべき
struct Widget {};

std::vector<bool> features(const Widget& w)
{
    std::vector<bool> v = { true, false, true, false, true };
    return v;
}

TEST(std_bool, features)
{
    Widget w;
    auto priorities = features(w)[4];

    EXPECT_STREQ("std::__1::__bit_reference<std::__1::vector<bool, std::__1::allocator<bool> >, true>",
                 boost::typeindex::type_id_with_cvr<decltype(priorities)>().pretty_name().c_str());

}
  • std::vector::referece が bool& の動作を模倣する技法はたくさんある
  • その一例が暗黙の型変換
bool priorities = features(w)[4];
  • auto 自体が問題ではなく、推論してほしい型を推論しないことが問題
    • よって目的の型への推論を強制すれば良い
    • それが、ETII (Explicitly typed initializer idiom)
auto priorities = std::static_cast<bool>(features(w)[4]);

NeoVim + dein の導入

はじめに

Mac にドキュメントエディタとして neovim を、neovim のプラグインマネージャとして dein をインストールします。

環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G4032

1. neovim のインストール

homebrew で一発インストール

$ brew install nvim
$ nvim -version
NVIM v0.4.3
Build type: Release
LuaJIT 2.0.5
Compilation: /usr/local/Homebrew/Library/Homebrew/shims/mac/super/clang -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -DNDEBUG -DMIN_LOG_LEVEL=3 -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wmissing-prototypes -Wimplicit-fallthrough -Wvla -fstack-protector-strong -fdiagnostics-color=auto -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -I/tmp/neovim-20191107-13403-1or2rj3/neovim-0.4.3/build/config -I/tmp/neovim-20191107-13403-1or2rj3/neovim-0.4.3/src -I/usr/local/include -I/tmp/neovim-20191107-13403-1or2rj3/neovim-0.4.3/deps-build/include -I/usr/local/opt/gettext/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/include -I/tmp/neovim-20191107-13403-1or2rj3/neovim-0.4.3/build/src/nvim/auto -I/tmp/neovim-20191107-13403-1or2rj3/neovim-0.4.3/build/include
Compiled by brew@Mojave.local

Features: +acl +iconv +tui
See ":help feature-compile"

      システム vimrc: "$VIM/sysinit.vim"
       省略時の $VIM: "/usr/local/Cellar/neovim/0.4.3/share/nvim"

Run :checkhealth for more info

2. neovim の設定

  • ~/.vimrc ではなく、~/.config/nvim/init.vim に設定を書きます。
  1. Configuration nvim-configuration

  2. Use $XDG_CONFIG_HOME/nvim/init.vim instead of .vimrc for configuration.

  3. Use $XDG_CONFIG_HOME/nvim instead of .vim to store configuration files.
  4. Use $XDG_DATA_HOME/nvim/shada/main.shada instead of .viminfo for persistent session information. |shada|

XDG_CONFIG_HOME

  • ユーザー個別の設定が書き込まれるディレクトリ (/etc と類似)。
  • デフォルトは $HOME/.config です。
$ mkdir ~/.config/nvim
  • ~/.config/nvim/init.vim の作成
" Configuration
colorscheme desert
filetype plugin indent on
syntax on
syntax enable
set termguicolors
set tabstop=4 softtabstop=4 expandtab shiftwidth=4 smarttab
set list
set listchars=tab:»-,trail:-,eol:,extends:»,precedes:«,nbsp:%
set number
set autoindent
set fenc=utf-8
set noswapfile
set autoread
set hidden
set showcmd
set cursorline
set cursorcolumn
set visualbell
set showmatch
set laststatus=2
set wildmode=list:longest

set ignorecase
set smartcase
set incsearch
set wrapscan

"" FileType
autocmd FileType python setl autoindent
autocmd FileType python setl smartindent cinwords=if,elif,else,for,while,try,except,finally,def,class
autocmd FileType python setl tabstop=8 expandtab shiftwidth=4 softtabstop=4
autocmd FileType r setl tabstop=4 expandtab shiftwidth=2 softtabstop=2
autocmd BufNewFile,BufRead *.gvy setfiletype groovy
autocmd BufNewFile,BufRead *.ts setfiletype typescript
autocmd BufNewFile,BufRead *.tsx,*.jsx setfiletype=typescript.tsx

"" Map Leader
let mapleader = "\<Space>"
let maplocalleader = "\<Space>"

"" Custom Key Mapping
nnoremap ; :
nnoremap : ;
inoremap <silent> jj <ESC>
nnoremap <Leader>o :CtrlP<CR>
nnoremap <Leader>w :w<CR>
vmap <Leader>y "+y
vmap <Leader>d "+d
nmap <Leader>p "+p
nmap <Leader>P "+P
vmap <Leader>p "+p
vmap <Leader>P "+P
nmap <Leader><Leader> V
map <C-n> ;NERDTreeToggle<CR>
nnoremap s <Nop>
nnoremap sj <C-w>j
nnoremap sk <C-w>k
nnoremap sl <C-w>l
nnoremap sh <C-w>h
nnoremap sJ <C-w>J
nnoremap sK <C-w>K
nnoremap sL <C-w>L
nnoremap sH <C-w>H
nnoremap sn gt
nnoremap sp gT
nnoremap sr <C-w>r
nnoremap s= <C-w>=
nnoremap sw <C-w>w
nnoremap so <C-w>_<C-w>|
nnoremap sO <C-w>=
nnoremap sN :<C-u>bn<CR>
nnoremap sP :<C-u>bp<CR>
nnoremap st :<C-u>tabnew<CR>
nnoremap sT :<C-u>Unite tab<CR>
nnoremap ss :<C-u>sp<CR>
nnoremap sv :<C-u>vs<CR>
nnoremap sq :<C-u>q<CR>
nnoremap sQ :<C-u>bd<CR>

3. dein.vim のインストール

$ curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
$ sh ./installer.sh ~/.cache/dein

4. dein.vim の設定

  • インストール後に表示される通り、以下の設定を ~/.config/nvim/init.vim に追記します。
"dein Scripts-----------------------------
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein')
  call dein#begin('~/.cache/dein')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/repos/github.com/Shougo/dein.vim')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
"if dein#check_install()
"  call dein#install()
"endif

"End dein Scripts-------------------------
if dein#load_state('~/.cache/dein')
  call dein#begin('~/.cache/dein')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/repos/github.com/Shougo/dein.vim')

+ call dein#load_toml('~/.config/nvim/dein.toml')
+ call dein#load_toml('~/.config/nvim/dein_lazy.toml', { 'lazy': 1 })

  " Required:
  call dein#end()
  call dein#save_state()
endif

CSV で Vector プロパティをロードする

環境

Oracle Graph Server Shell 20.1.0
PGX server version: 19.4.0 type: SM
PGX server API version: 3.6.0
PGQL version: 1.2

前提

  • Pgx Server で allow_local_filesystem が true になっており、かつ datasource_dir_whitelist/opt/oracle/oradata ディレクトリが指定されている
$ cat /etc/oracle/graph/pgx.conf
{
  "allow_local_filesystem": true,
  "datasource_dir_whitelist": ["/opt/oracle/oradata"],
...
}
  • Pgx Server が稼働するサーバの /opt/oracle/oradata/opt/oracle/oradata/sample.vertices.csv/opt/oracle/oradata/sample.edges.csv が格納されている。

/opt/oracle/oradata/vector_props.vertices.csv

1,1;2;3,0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40;41;42;43;44;45;46;47;48;49;50;51;52;53;54;55;56;57;58;59;60;61;62;63;64;65;66;67;68;69;70;71;72;73;74;75;76;77;78;79;80;81;82;83;84;85;86;87;88;89;90;91;92;93;94;95;96;97;98;99,0.0;0.01;0.02;0.03;0.04;0.05;0.06;0.07;0.08;0.09;0.1;0.11;0.12;0.13;0.14;0.15;0.16;0.17;0.18;0.19;0.2;0.21;0.22;0.23;0.24;0.25;0.26;0.27;0.28;0.29;0.3;0.31;0.32;0.33;0.34;0.35;0.36;0.37;0.38;0.39;0.4;0.41;0.42;0.43;0.44;0.45;0.46;0.47;0.48;0.49;0.5;0.51;0.52;0.53;0.54;0.55;0.56;0.57;0.58;0.59;0.6;0.61;0.62;0.63;0.64;0.65;0.66;0.67;0.68;0.69;0.7;0.71;0.72;0.73;0.74;0.75;0.76;0.77;0.78;0.79;0.8;0.81;0.82;0.83;0.84;0.85;0.86;0.87;0.88;0.89;0.9;0.91;0.92;0.93;0.94;0.95;0.96;0.97;0.98;0.99,"hoge0;hoge1;hoge2;hoge3;hoge4;hoge5;hoge6;hoge7;hoge8;hoge9;hoge10;hoge11;hoge12;hoge13;hoge14;hoge15;hoge16;hoge17;hoge18;hoge19;hoge20;hoge21;hoge22;hoge23;hoge24;hoge25;hoge26;hoge27;hoge28;hoge29;hoge30;hoge31;hoge32;hoge33;hoge34;hoge35;hoge36;hoge37;hoge38;hoge39;hoge40;hoge41;hoge42;hoge43;hoge44;hoge45;hoge46;hoge47;hoge48;hoge49;hoge50;hoge51;hoge52;hoge53;hoge54;hoge55;hoge56;hoge57;hoge58;hoge59;hoge60;hoge61;hoge62;hoge63;hoge64;hoge65;hoge66;hoge67;hoge68;hoge69;hoge70;hoge71;hoge72;hoge73;hoge74;hoge75;hoge76;hoge77;hoge78;hoge79;hoge80;hoge81;hoge82;hoge83;hoge84;hoge85;hoge86;hoge87;hoge88;hoge89;hoge90;hoge91;hoge92;hoge93;hoge94;hoge95;hoge96;hoge97;hoge98;hoge99"

/opt/oracle/oradata/vector_props.edges.csv

1,2,1;2;3

CSV ファイルをロードする

var gcb = GraphConfigBuilder.forFileFormat(Format.CSV).
            addVertexUri("/opt/oracle/oradata/vector_props.vertices.csv").
            addEdgeUri("/opt/oracle/oradata/vector_props.edges.csv")

// Vector タイプの PropertyType. 第三引数で次元を指定
gcb.addVertexVectorProperty("vp_vector_int", PropertyType.INTEGER, 3)
gcb.addVertexVectorProperty("vp_vector_long", PropertyType.LONG, 100)
gcb.addVertexVectorProperty("vp_vector_double", PropertyType.DOUBLE, 100)
gcb.addVertexVectorProperty("vp_vector_string", PropertyType.STRING, 100)
gcb.addEdgeVectorProperty("ep_vector_int", PropertyType.INTEGER, 3)

var g = session.readGraphWithProperties(gcb.build())

// Vector 型のプロパティの値の取り出し方
var vec_v_int_prop = g.getVertex(1).getProperty("vp_vector_int")
// => vec_v_int_prop ==> PgxVect[type=integer,dimension=3]

var vec_v_int = (oracle.pgx.common.util.vector.Vect<Integer>) (vec_v_int_prop)
/*
 * |  Warning:
 * |  unchecked cast
 * |    required: oracle.pgx.common.util.vector.Vect<java.lang.Integer>
 * |    found:    java.lang.Object
 * |  var vec_v_int = (oracle.pgx.common.util.vector.Vect<Integer>) (vec_v_int_prop);
 * |                                                                ^--------------^
 * vec_v_int ==> PgxVect[type=integer,dimension=3]
 */

vec_v_int.toArray()
// $231 ==> Integer[3] { 1, 2, 3 }

// String 型の vector は java.lang.NullPointerException が発生する
g.getVertex(1).getProperty("vp_vector_string")
/*
 *  Exception java.util.concurrent.ExecutionException: java.lang.NullPointerException
 *|        at CompletableFuture.reportGet (CompletableFuture.java:395)
 *|        at CompletableFuture.get (CompletableFuture.java:1999)
 *|        at PgxFuture.get (PgxFuture.java:99)
 *|        at PgxEntity.getProperty (PgxEntity.java:280)
 *|        at (#284:1)
 *|  Caused by: java.lang.NullPointerException
 *|        at PgxEntity.lambda$getPropertyAsync$1 (PgxEntity.java:191)
 *|        at CompletableFuture$UniCompose.tryFire (CompletableFuture.java:1072)
 *|        at CompletableFuture.postComplete (CompletableFuture.java:506)
 *|        at CompletableFuture.complete (CompletableFuture.java:2073)
 *|        at PgxFuture.completeWithResultOrException (PgxFuture.java:55)
 *|        at CompletableFuture.uniWhenComplete (CompletableFuture.java:859)
 *|        at CompletableFuture$UniWhenComplete.tryFire (CompletableFuture.java:837)
 *|        at CompletableFuture.postComplete (CompletableFuture.java:506)
 *|        at CompletableFuture.complete (CompletableFuture.java:2073)
 *|        at PgxRemoteFuture.executeRequest (PgxRemoteFuture.java:107)
 *|        at PgxRemoteFuture.lambda$fetchRemoteResultAsync$3 (PgxRemoteFuture.java:218)
 *|        at ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1128)
 *|        at ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:628)
 *|        at Thread.run (Thread.java:834)
 */

Graph Config Json からロードする方法

  • クライアント側に以下の JSON ファイルを用意する (/tmp/vector_prps_csv.json)
{
    "format": "csv",
    "edge_props": [{
        "type": "integer",
        "name": "ep_vector_int",
        "dimension": 3
    }],
    "error_handling": {},
    "vertex_id_type": "integer",
    "vertex_uris": ["/opt/oracle/oradata/vector_props.vertices.csv"],
    "attributes": {},
    "edge_uris": ["/opt/oracle/oradata/vector_props.edges.csv"],
    "loading": {},
    "vertex_props": [{
        "type": "integer",
        "name": "vp_vector_int",
        "dimension": 3
    }, {
        "type": "long",
        "name": "vp_vector_long",
        "dimension": 100
    }, {
        "type": "double",
        "name": "vp_vector_double",
        "dimension": 100
    }]
}
  • PGX Client を起動して、Graph をロードする
// Graph Config Json ファイルは PGX Client 側に配置されているものを読みにいく
var g = session.readGraphWithProperties("/tmp/vector_props_csv.json")

ローカルにある CSV で Graph をロードする

環境

Oracle Graph Server Shell 20.1.0
PGX server version: 19.4.0 type: SM
PGX server API version: 3.6.0
PGQL version: 1.2

前提

  • Pgx Server で allow_local_filesystem が true になっており、かつ datasource_dir_whitelist/opt/oracle/oradata ディレクトリが指定されている
$ cat /etc/oracle/graph/pgx.conf
{
  "allow_local_filesystem": true,
  "datasource_dir_whitelist": ["/opt/oracle/oradata"],
...
}
  • Pgx Server が稼働するサーバの /opt/oracle/oradata/opt/oracle/oradata/sample.vertices.csv/opt/oracle/oradata/sample.edges.csv が格納されている。

/opt/oracle/oradata/sample.vertices.csv

1,VL,0.1,1,1,true,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.1,"hoge",2,4
2,VL,-2.0,2,100000000000000000,false,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.2,"hage",3,1
3,VL,0.3,-3,-2222222222222222,false,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.3,"hige",4,4
4,VL,4.56789,3,-3333333333333,true,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.4,"huga",1,2

/opt/oracle/oradata/sample.edges.csv

1,2,EL,0.1,1,1,true,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.1,"hoge",2,4
2,1,EL,-2.0,2,100000000000000000,false,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.2,"hage",3,1
2,3,EL,0.3,-3,-2222222222222222,false,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.3,"hige",4,4
4,2,EL,4.56789,3,-3333333333333,true,2020-04-20,23:59:59.000000059,2020-04-20T16:46:40.000000300,2020-11-11T01:01:01.000000001+09:00,23:30:30.000000030+09:00,0.4,"huga",1,2

CSV ファイルをロードする

var gcb = GraphConfigBuilder.forFileFormat(Format.CSV).
                addVertexUri("/opt/oracle/oradata/sample.vertices.csv").
                addEdgeUri("/opt/oracle/oradata/sample.edges.csv").
                setVertexIdType(IdType.INTEGER).
                setTimeFormat(Arrays.asList("HH:mm:ss.SSSSSSSSS")).
                setTimeWithTimezoneFormat(Arrays.asList("HH:mm:ss.SSSSSSSSSXXX")).
                setTimestampFormat(Arrays.asList("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS")).
                setTimestampWithTimezoneFormat(Arrays.asList("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX"))

// Vertex Properties
gcb.addVertexProperty("vp_double",    PropertyType.DOUBLE)
gcb.addVertexProperty("vp_integer",   PropertyType.INTEGER)
gcb.addVertexProperty("vp_long",      PropertyType.LONG)
gcb.addVertexProperty("vp_boolean",   PropertyType.BOOLEAN)
gcb.addVertexProperty("vp_local_date",PropertyType.LOCAL_DATE)
gcb.addVertexProperty("vp_time",      PropertyType.TIME)
gcb.addVertexProperty("vp_timestamp", PropertyType.TIMESTAMP)
gcb.addVertexProperty("vp_timestamp_with_timezone", PropertyType.TIMESTAMP_WITH_TIMEZONE)
gcb.addVertexProperty("vp_time_with_timezone", PropertyType.TIME_WITH_TIMEZONE)
gcb.addVertexProperty("vp_float",     PropertyType.FLOAT)
gcb.addVertexProperty("vp_string",    PropertyType.STRING)
gcb.addVertexProperty("vp_vertex",    PropertyType.VERTEX)
gcb.addVertexProperty("vp_edge",      PropertyType.EDGE)

// Edge Properties
gcb.addEdgeProperty("ep_double",    PropertyType.DOUBLE)
gcb.addEdgeProperty("ep_integer",   PropertyType.INTEGER)
gcb.addEdgeProperty("ep_long",      PropertyType.LONG)
gcb.addEdgeProperty("ep_boolean",   PropertyType.BOOLEAN)
gcb.addEdgeProperty("ep_local_date",PropertyType.LOCAL_DATE)
gcb.addEdgeProperty("ep_time",      PropertyType.TIME)
gcb.addEdgeProperty("ep_timestamp", PropertyType.TIMESTAMP)
gcb.addEdgeProperty("ep_timestamp_with_timezone", PropertyType.TIMESTAMP_WITH_TIMEZONE)
gcb.addEdgeProperty("ep_time_with_timezone", PropertyType.TIME_WITH_TIMEZONE)
gcb.addEdgeProperty("ep_float",      PropertyType.FLOAT)
gcb.addEdgeProperty("ep_string",      PropertyType.STRING)
gcb.addEdgeProperty("ep_vertex",      PropertyType.VERTEX)
gcb.addEdgeProperty("ep_edge",      PropertyType.EDGE)

// Label
gcb.setLoadVertexLabels(true)
gcb.setLoadEdgeLabel(true)

var g = session.readGraphWithProperties(gcb.build())

Graph Config Json からロードする方法

  • クライアント側に以下の JSON ファイルを用意する (/tmp/sample_csv.json)
{
    "attributes": {},
    "error_handling": {},
    "timestamp_with_timezone_format": ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX"],
    "vertex_props": [{
        "type": "double",
        "dimension": 0,
        "name": "vp_double"
    }, {
        "type": "integer",
        "dimension": 0,
        "name": "vp_integer"
    }, {
        "type": "long",
        "dimension": 0,
        "name": "vp_long"
    }, {
        "type": "boolean",
        "dimension": 0,
        "name": "vp_boolean"
    }, {
        "type": "local_date",
        "dimension": 0,
        "name": "vp_local_date"
    }, {
        "type": "time",
        "dimension": 0,
        "name": "vp_time"
    }, {
        "type": "timestamp",
        "dimension": 0,
        "name": "vp_timestamp"
    }, {
        "type": "timestamp_with_timezone",
        "dimension": 0,
        "name": "vp_timestamp_with_timezone"
    }, {
        "type": "time_with_timezone",
        "dimension": 0,
        "name": "vp_time_with_timezone"
    }, {
        "type": "float",
        "dimension": 0,
        "name": "vp_float"
    }, {
        "type": "string",
        "dimension": 0,
        "name": "vp_string"
    }, {
        "type": "vertex",
        "dimension": 0,
        "name": "vp_vertex"
    }, {
        "type": "edge",
        "dimension": 0,
        "name": "vp_edge"
    }],
    "format": "csv",
    "timestamp_format": ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS"],
    "time_format": ["HH:mm:ss.SSSSSSSSS"],
    "vertex_id_type": "integer",
    "loading": {
        "load_vertex_labels": true,
        "load_edge_label": true
    },
    "vertex_uris": ["/opt/oracle/oradata/sample.vertices.csv"],
    "edge_props": [{
        "type": "double",
        "dimension": 0,
        "name": "ep_double"
    }, {
        "type": "integer",
        "dimension": 0,
        "name": "ep_integer"
    }, {
        "type": "long",
        "dimension": 0,
        "name": "ep_long"
    }, {
        "type": "boolean",
        "dimension": 0,
        "name": "ep_boolean"
    }, {
        "type": "local_date",
        "dimension": 0,
        "name": "ep_local_date"
    }, {
        "type": "time",
        "dimension": 0,
        "name": "ep_time"
    }, {
        "type": "timestamp",
        "dimension": 0,
        "name": "ep_timestamp"
    }, {
        "type": "timestamp_with_timezone",
        "dimension": 0,
        "name": "ep_timestamp_with_timezone"
    }, {
        "type": "time_with_timezone",
        "dimension": 0,
        "name": "ep_time_with_timezone"
    }, {
        "type": "float",
        "dimension": 0,
        "name": "ep_float"
    }, {
        "type": "string",
        "dimension": 0,
        "name": "ep_string"
    }, {
        "type": "vertex",
        "dimension": 0,
        "name": "ep_vertex"
    }, {
        "type": "edge",
        "dimension": 0,
        "name": "ep_edge"
    }],
    "edge_uris": ["/opt/oracle/oradata/sample.edges.csv"],
    "time_with_timezone_format": ["HH:mm:ss.SSSSSSSSSXXX"]
}
  • PGX Client を起動して、Graph をロードする
// Graph Config Json ファイルは PGX Client 側に配置されているものを読みにいく
var g = session.readGraphWithProperties("/tmp/sample_csv.json")

Vector プロパティをセットする方法

環境

Oracle Graph Server Shell 20.1.0
PGX server version: 19.4.0 type: SM
PGX server API version: 3.6.0
PGQL version: 1.2

準備

  • Graph の作成
var g = session.<Integer>newGraphBuilder(IdType.INTEGER).addVertex(1).build()

Vector プロパティの設定方法

// Vector Integer プロパティの作成
g.createVertexVectorProperty(PropertyType.INTEGER, 3 /* dimension */, "vp_vec_int")

// Vector Integer プロパティのセット
g.getVertex(1).setProperty("vp_vec_int", new oracle.pgx.api.PgxVect<Integer>(new Integer[]{1,2,3}))
// Vector Long プロパティの作成
g.createVertexVectorProperty(PropertyType.LONG, 3 /* dimension */, "vp_vec_long")

// Vector Long プロパティのセット
g.getVertex(1).setProperty("vp_vec_long", new oracle.pgx.api.PgxVect<Long>(new Long[]{1L,2L,3L}))
// Vector Float プロパティの作成
g.createVertexVectorProperty(PropertyType.FLOAT, 3 /* dimension */, "vp_vec_float")

// Vector Float プロパティのセット
g.getVertex(1).setProperty("vp_vec_float", new oracle.pgx.api.PgxVect<Float>(new Float[]{0.1f,0.2f,0.3f}))
// Vector Double プロパティの作成
g.createVertexVectorProperty(PropertyType.DOUBLE, 3 /* dimension */, "vp_vec_double")

// Vector Double プロパティのセット
g.getVertex(1).setProperty("vp_vec_double", new oracle.pgx.api.PgxVect<Double>(new Double[]{0.1d,0.2d,0.3d}))
  • Vector String プロパティのセットはできない
// Vector String プロパティの作成
g.createVertexVectorProperty(PropertyType.STRING, 3 /* dimension */, "vp_vec_string")

// Vector String プロパティのセット -> エラー発生
g.getVertex(1).setProperty("vp_vec_string", new oracle.pgx.api.PgxVect<String>(new String[]{"str1", "str2", "str3}))

|  Exception java.lang.IllegalArgumentException: type string is not a valid vector property type
|        at PgxVect.<init> (PgxVect.java:49)
|        at (#23:1)

Vector プロパティの参照方法

((oracle.pgx.common.util.vector.Vect<Integer>)g.getVertex(1).getProperty("vp_vec_int")).toArray()
|  Warning:
|  unchecked cast
|    required: oracle.pgx.common.util.vector.Vect<java.lang.Integer>
|    found:    java.lang.Object
|  ((oracle.pgx.common.util.vector.Vect<Integer>)g.getVertex(1).getProperty("vp_vec_int")).toArray()
|                                                ^--------------------------------------^
$28 ==> Integer[3] { 1, 2, 3 }
((oracle.pgx.common.util.vector.Vect<Long>)g.getVertex(1).getProperty("vp_vec_long")).toArray()
|  Warning:
|  unchecked cast
|    required: oracle.pgx.common.util.vector.Vect<java.lang.Long>
|    found:    java.lang.Object
|  ((oracle.pgx.common.util.vector.Vect<Long>)g.getVertex(1).getProperty("vp_vec_long")).toArray()
|                                             ^---------------------------------------^
$29 ==> Long[3] { 1, 2, 3 }
((oracle.pgx.common.util.vector.Vect<Double>)g.getVertex(1).getProperty("vp_vec_double")).toArray()
|  Warning:
|  unchecked cast
|    required: oracle.pgx.common.util.vector.Vect<java.lang.Double>
|    found:    java.lang.Object
|  ((oracle.pgx.common.util.vector.Vect<Double>)g.getVertex(1).getProperty("vp_vec_double")).toArray()
|                                               ^-----------------------------------------^
$30 ==> Double[3] { 0.1, 0.2, 0.3 }
((oracle.pgx.common.util.vector.Vect<Float>)g.getVertex(1).getProperty("vp_vec_float")).toArray()
|  Warning:
|  unchecked cast
|    required: oracle.pgx.common.util.vector.Vect<java.lang.Float>
|    found:    java.lang.Object
|  ((oracle.pgx.common.util.vector.Vect<Float>)g.getVertex(1).getProperty("vp_vec_float")).toArray()
|                                              ^----------------------------------------^
$31 ==> Float[3] { 0.1, 0.2, 0.3 }

実践 Rust 入門 第4章プリミティブ型

Rust における型

  • すべての値の型はコンパイル時に決定される
    • これは安全性、効率性という利点がある
      • 安全性: エラーの早期発見、所有権システムとの連携による型安全かつデータ競合のないプログラム開発の促進
      • 効率性: メモリの細かい制御、コンパイラによる最適化の恩恵

型の分類

  • 定義による分類

    • プリミティブ型
    • ユーザ定義型
  • 構成による分類

    • スカラ型
    • 複合型

スカラ型

  • ユニット
  • 真理値
  • 固定精度の整数
  • 固定精度の浮動小数
  • 文字
  • 参照
  • 生ポインタ
  • 関数ポイント
let n = 40;
let c = 'R';

ユニット

  • 値を返さない関数の戻り値はユニット型
  • ユニット型は意味のある情報を持たないため、サイズは0
    • キーバリューのペアを格納するデータ構造でキーのみデータを保持したい場合には、バリューにユニットを格納すると無駄にメモリを消費しない
assert_eq!(std::mem::size_of::<()>(), 0);

真偽値

  • true と false を持つ
    let b1 = true;
    let b2 = !b1;
    let n1 = 1;
    let n2 = 2;

    let b3 = n1 >= n2;
    let b4 = n1 < n2;
    let b5 = b3 && b4;
    let b6 = b3 || b4;

固定精度の整数

  • ビット幅指定の整数型
    • 符号なし (uxx)
    • 符号あり (ixx)
let n1: i32 = 32;
  • アドレス幅の整数型
    • usize
    • isize
let n2: usize = 32;
  • 整数リテラル
    • デフォルト10進数
    • プレフィクスで他の基数に基づく数を表される
      • 0x: 16進数
      • 0o: 8進数
      • 0b: 2進数
let h1 = 0xff;
let o1 = 0o744;
let b1 = 0b1010_0110_1110_1001;
let n1 = 10u8;
let n2 = b'A';
assert_eq!(n2, 65u8);
  • 代表的な整数演算

    • よくある算術演算、ビット演算、複合代入演算、比較演算は利用可能 
    • Cで使えるけど Rust で使用できないものは以下の2つ
  • 整数型のメソッドや定数

    • 整数型のメソッド
    • pow(), abs(), rotate_left(), from_str(), to_string(), checked_add()
    • 定数
    • 最大値 MAX 等
  • 整数演算の桁あふれ

  • リリースモードでは桁あふれは検出できない
    • 以下の方法で対応するメソッドを使用することを検討する
      • 検査付き演算
      • 飽和演算
      • ラッピング演算
      • 桁あふれ演算
fn overflow_calc() {
    let n1 = 200u8;
    let n2 = 3u8;

    assert_eq!(n1.checked_mul(n2), None);
    assert_eq!(n1.saturating_mul(n2), std::u8::MAX);
    assert_eq!(n1.wrapping_mul(n2), 88);
    assert_eq!(n1.overflowing_mul(n2), (88, true));
}

固定精度の浮動小数

  • ビット数に応じてf32, f64の2つの型が用意されている
  • サフィックスで型を指定可能
  • 指数部も指定可能
    let f1 = 10.0;
    let f2 = 1_234.897f64;
    let f3 = 576.6E77;

文字

  • 1つのUnicodeのスカラ値
  • シングルクォートで囲む
  • 1文字を表すのにたとえ英数字であっても4バイトを消費する
  • 複数のコードポイントが組み合わされた文字例えば'が'などは char リテラルとして使用することはできない(コンパイルエラー)
    let c1 = 'A';
    let c2 = 'B';

    assert!(c1 <= c2);
    assert!(c1.is_uppercase());

    let c3 = '0';
    assert!(c3.is_digit(10));

    let c4 = '\t';
    let c5 = '\'';
    let c6 = '\\';
    let c7 = '\x7F';

    let c8 = '漢';
    let c9 = '\u{5b57}';
    let c10 = '\u{1f600}';
    println!("{}", c10);

参照

  • メモリ安全ポインタ
    • データが格納されている場所を指す
    • usize と同じビット幅の整数で表される
    fn f1(mut n: u32){
        n = 1;
        println!("{}", n);
    }

    fn f2(n_ptr: &mut u32){
        println!("f2: n_ptr {:p}", n_ptr);
        *n_ptr = 2;
        println!("{}", n_ptr);
    }

    let mut f_n1 = 0;
    f1(f_n1);
    println!("{}", f_n1);
    f2(&mut f_n1);
    println!("{}", f_n1);

生ポインタ

  • メモリ安全ではないポインタ
  • dereference するときに unsafe ブロック内に処理を記述する必要性がある
    let mut c1 = 'A';
    let c1_ptr: *mut char = &mut c1;

    assert_eq!(unsafe{*c1_ptr}, 'A');

    unsafe {
        *c1_ptr = 'B';
    }

関数ポインタ

  • 関数を指すポインタ
  fn double(n: i32) -> i32 {
      n + n
  }

  fn abs(n: i32) -> i32 {
      if n >= 0 { n } else { -n } 
  }

  let f1: fn(i32) -> i32 = double;
  let f2: fn(i32) -> i32 = abs;

  assert_eq!(std::mem::size_of_val(&f1), std::mem::size_of::<usize>());

  let mut f3 = double;
  assert_eq!(std::mem::size_of_val(&f3), 0);