s_matrix 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 873b7c7f5cf89a315b84cd9b373923819962522c
4
- data.tar.gz: 9706ed9b6207ddeba5970c09ba027c6bc0739b62
3
+ metadata.gz: d0a1d9986c5eee4c83153245c8ecb30da21d3609
4
+ data.tar.gz: 8cd70ce3cf6a73ac9acb964b3bb7483979c1686e
5
5
  SHA512:
6
- metadata.gz: 5015507f5e37081199965b0098dc2ee9d0f6e4df0bab055c55d159bbb1127b6e9295e36350586634980d140ab80adcfdc3906a7a8b33aff6f4156bec27518793
7
- data.tar.gz: c16ea95270874368b5c53f531f455d1c2abef4e3412c335860a8b3b2e8c754be8187694b3eb20d5778335b55dc59b7e9b10f0533a0ee00a660f420486fa2712e
6
+ metadata.gz: 6840c3d37d7b86ebb9c2034a7cf295587daff1ac5be8273a2c8bf3eabf33593b0ab334807c9dc3bfaa8dfec2817d312ec017371e15f93bf8f77e728dc678ce52
7
+ data.tar.gz: 2b33b8b9209bf4c262ea642684bc2332d326e30fc0cecedf5b72c56b10d6958b52f280a0df37cf22862fdbb971244922e4262ac216ae2a6e671e777add55bdb9
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
- Current version 1.0.0
2
- Latest stable version is 1.0.0
1
+ Current version 1.0.2
3
2
 
4
3
  ### Matrix reduce memory usage for large Hash.
5
4
  Matrix store the hash like this: <br>
@@ -46,16 +45,21 @@ Or install it yourself as:
46
45
  EQUIPMENTS.size.should == 2
47
46
  # or you can use get\_row instead of []<br>
48
47
  EQUIPMENTS.get\_row('20002')<br>
49
- # each
50
- EQUIPMENTS.each {|k, v| k == '10001', v == {'id' => '10001', 'name' => 'sword', ...} }
51
- # all
52
- EQUIPMENTS.all.should == { '20002' => {'id' => '10002', 'name' => 'shoe', 'speed' => '5'}, '20003' => {} }
53
- # ids
54
- EQUIPMENTS.ids.should == ['20002', '20003']
55
- # keys
56
- EQUIPMENTS.keys.should == ['id', 'name', 'hp']
57
- # to\_s for debug
58
- puts EQUIPMENTS.to_s
48
+ # each<br>
49
+ EQUIPMENTS.each {|k, v| k == '10001', v == {'id' => '10001', 'name' => 'sword', ...} }<br>
50
+ # all<br>
51
+ EQUIPMENTS.all.should == { '20002' => {'id' => '10002', 'name' => 'shoe', 'speed' => '5'}, '20003' => {} }<br>
52
+ # first<br>
53
+ EQUIPMENTS.first.should == ['20002', {'id' => '10002', 'name' => 'shoe', 'speed' => '5'}]
54
+ # ids<br>
55
+ EQUIPMENTS.ids.should == ['20002', '20003']<br>
56
+ # keys<br>
57
+ EQUIPMENTS.keys.should == ['id', 'name', 'hp']<br>
58
+ # find -- find the first one<br>
59
+ EQUIPMENTS.find({name: 'shoe'}).should == ['20002', {'id' => '10002', 'name' => 'shoe', 'speed' => '5'}]
60
+ # to\_s for debug<br>
61
+ puts EQUIPMENTS.to_s<br>
62
+
59
63
 
60
64
  ### todolist
61
65
  https://github.com/libinzhangyuan/s\_matrix/blob/master/todolist.txt
@@ -5,6 +5,8 @@
5
5
  #include "stdio.h"
6
6
 
7
7
 
8
+ bool GMatx::t_continue = true;
9
+ bool GMatx::t_break = false;
8
10
  GMatx::GMatx(void)
9
11
  {
10
12
  }
@@ -43,7 +45,6 @@ const std::vector<std::string>& GMatx::get_titles(void) const
43
45
  return m_titles.get_titles();
44
46
  }
45
47
 
46
- // typedef void (*each_call_func)(const std::string& /*key*/, const t_key_value_hash& /*row_content*/, void* args);
47
48
  void GMatx::each_call(each_call_func func, void* args) const
48
49
  {
49
50
  const std::vector<std::string>& titles = m_titles.get_titles();
@@ -52,7 +53,8 @@ void GMatx::each_call(each_call_func func, void* args) const
52
53
  {
53
54
  const std::string& id = iter->first;
54
55
  const MatxRow& row = iter->second;
55
- func(id, row.to_key_value_hash(titles), args);
56
+ if (func(id, row.to_key_value_hash(titles), args) == GMatx::t_break)
57
+ break;
56
58
  }
57
59
  }
58
60
 
@@ -70,3 +72,19 @@ size_t GMatx::size(void) const
70
72
  {
71
73
  return m_contents.size();
72
74
  }
75
+
76
+ t_key_value_hash GMatx::first(std::string& id_out) const
77
+ {
78
+ t_key_value_hash result;
79
+
80
+ // empty matx.
81
+ //
82
+ std::map<std::string /* id */, MatxRow>::const_iterator iter = m_contents.begin();
83
+ if (iter == m_contents.end())
84
+ return result;
85
+
86
+ id_out = iter->first;
87
+ const MatxRow& row = iter->second;
88
+ const std::vector<std::string>& titles = m_titles.get_titles();
89
+ return row.to_key_value_hash(titles);
90
+ }
data/ext/s_matrix/gmatx.h CHANGED
@@ -19,9 +19,14 @@ public:
19
19
  std::string to_s(void) const;
20
20
  size_t size(void) const;
21
21
 
22
+ t_key_value_hash first(std::string& id_out) const;
23
+
22
24
  // iterator function
23
25
  // the args parameter of each_call function will pass to callback function each_call_func.
24
- typedef void (*each_call_func)(const std::string& /*key*/, const t_key_value_hash& /*row_content*/, void* args);
26
+ // the return of each_call_func indicate continue iterator or not. - true means continue. false means break.
27
+ static bool t_continue;
28
+ static bool t_break;
29
+ typedef bool (*each_call_func)(const std::string& /*id*/, const t_key_value_hash& /*row_content*/, void* args);
25
30
  void each_call(each_call_func func, void* args) const;
26
31
 
27
32
  private:
@@ -0,0 +1,62 @@
1
+ #include <sstream>
2
+
3
+ #include "matx_hash_util.h"
4
+ #include "stdio.h"
5
+ #include "matx_row.h"
6
+
7
+ namespace MatxHashUtil
8
+ {
9
+
10
+ VALUE key_value_hash_to_ruby_hash(const t_key_value_hash& row_hash)
11
+ {
12
+ VALUE ret_hash = rb_hash_new();
13
+ for (t_key_value_hash::const_iterator iter = row_hash.begin(); iter != row_hash.end(); ++iter)
14
+ {
15
+ const std::string& key = iter->first;
16
+ const std::string& value = iter->second;
17
+ if (value == MatxRow::null_string)
18
+ rb_hash_aset(ret_hash, rb_str_new_cstr(key.c_str()), Qnil);
19
+ else
20
+ rb_hash_aset(ret_hash, rb_str_new_cstr(key.c_str()), rb_str_new_cstr(value.c_str()));
21
+ }
22
+ return ret_hash;
23
+ }
24
+
25
+ int hash_iter_func(VALUE key, VALUE value, VALUE p_row_hash)
26
+ {
27
+ t_key_value_hash* p_hash = (t_key_value_hash*)p_row_hash;
28
+
29
+ // key
30
+ VALUE key_str = rb_funcall(key, rb_intern("to_s"), 0);
31
+
32
+ // value
33
+ std::string str_value;
34
+ if (TYPE(value) == T_NIL)
35
+ str_value = MatxRow::null_string;
36
+ else
37
+ {
38
+ VALUE rb_str = rb_funcall(value, rb_intern("to_s"), 0);
39
+ str_value = StringValueCStr( rb_str );
40
+ }
41
+
42
+ (*p_hash)[StringValueCStr(key_str)] = str_value;
43
+ return ST_CONTINUE;
44
+ }
45
+
46
+ t_key_value_hash rb_hash_to_key_value_hash(VALUE rb_hash)
47
+ {
48
+ t_key_value_hash row_hash;
49
+ rb_hash_foreach(rb_hash, (int (*)(ANYARGS))hash_iter_func, (VALUE)&row_hash);
50
+ return row_hash;
51
+ }
52
+
53
+ std::string key_value_hash_to_str(const t_key_value_hash& row_hash)
54
+ {
55
+ std::ostringstream ostr;
56
+ ostr << "--row_hash: size = " << row_hash.size() << std::endl;
57
+ for (t_key_value_hash::const_iterator iter = row_hash.begin(); iter!= row_hash.end(); ++iter)
58
+ ostr << iter->first << " -> " << iter->second << std::endl;
59
+ ostr << std::endl;
60
+ return ostr.str();
61
+ }
62
+ }
@@ -0,0 +1,20 @@
1
+ #ifndef _MATX_HASH_UTIL_H_
2
+ #define _MATX_HASH_UTIL_H_
3
+
4
+ #include <string>
5
+ #include <map>
6
+ #include "matx_type_def.h"
7
+
8
+ #include "ruby.h"
9
+
10
+ namespace MatxHashUtil
11
+ {
12
+ VALUE key_value_hash_to_ruby_hash(const t_key_value_hash& row_hash);
13
+ t_key_value_hash rb_hash_to_key_value_hash(VALUE rb_hash);
14
+
15
+ std::string key_value_hash_to_str(const t_key_value_hash& row_hash);
16
+ }
17
+
18
+
19
+
20
+ #endif // _MATX_HASH_UTIL_H_
@@ -4,6 +4,7 @@
4
4
  #include "ruby/util.h"
5
5
 
6
6
  #include "gmatx.h"
7
+ #include "matx_hash_util.h"
7
8
 
8
9
  static VALUE t_init(VALUE self);
9
10
  static VALUE t_init_copy(VALUE self, VALUE orig);
@@ -51,19 +52,6 @@ static VALUE sm_alloc(VALUE klass)
51
52
  return Data_Wrap_Struct(klass, 0, free_matx, pMatx);
52
53
  }
53
54
 
54
- static int t_add_row_hash_iter_func(VALUE key, VALUE value, VALUE p_row_hash)
55
- {
56
- t_key_value_hash* p_hash = (t_key_value_hash*)p_row_hash;
57
-
58
- VALUE key_str = rb_funcall(key, rb_intern("to_s"), 0);
59
- VALUE value_str = rb_funcall(value, rb_intern("to_s"), 0);
60
- //printf("key: %s, value: %s, p_hash size %lu\n", StringValueCStr(key_str), StringValueCStr(value_str), p_hash->size());
61
-
62
- (*p_hash)[StringValueCStr(key_str)] = StringValueCStr(value_str);
63
- return ST_CONTINUE;
64
- }
65
-
66
-
67
55
  // row: {hp: 23, name: '2332342', 'text' => 'fsdfsd'}
68
56
  static VALUE t_add_row(VALUE self, VALUE id, VALUE row)
69
57
  {
@@ -80,8 +68,7 @@ static VALUE t_add_row(VALUE self, VALUE id, VALUE row)
80
68
 
81
69
  // 处理row deal with row
82
70
  //
83
- t_key_value_hash row_hash;
84
- rb_hash_foreach(row, (int (*)(ANYARGS))t_add_row_hash_iter_func, (VALUE)&row_hash);
71
+ const t_key_value_hash& row_hash = MatxHashUtil::rb_hash_to_key_value_hash(row);
85
72
 
86
73
  // 存数据 store data
87
74
  //
@@ -93,21 +80,6 @@ static VALUE t_add_row(VALUE self, VALUE id, VALUE row)
93
80
  return self;
94
81
  }
95
82
 
96
- static VALUE row_hash_to_ruby_hash(const t_key_value_hash& row_hash)
97
- {
98
- VALUE ret_hash = rb_hash_new();
99
- for (t_key_value_hash::const_iterator iter = row_hash.begin(); iter != row_hash.end(); ++iter)
100
- {
101
- const std::string& key = iter->first;
102
- const std::string& value = iter->second;
103
- if (value == MatxRow::null_string)
104
- rb_hash_aset(ret_hash, rb_str_new_cstr(key.c_str()), Qnil);
105
- else
106
- rb_hash_aset(ret_hash, rb_str_new_cstr(key.c_str()), rb_str_new_cstr(value.c_str()));
107
- }
108
- return ret_hash;
109
- }
110
-
111
83
  static VALUE t_get_row(VALUE self, VALUE id)
112
84
  {
113
85
  // 处理id deal with id
@@ -123,12 +95,69 @@ static VALUE t_get_row(VALUE self, VALUE id)
123
95
  Data_Get_Struct(self, class GMatx, pMatx);
124
96
 
125
97
  t_key_value_hash row_hash = pMatx->get_row(std::string(p_id_c_str));
126
- return row_hash_to_ruby_hash(row_hash);
98
+ return MatxHashUtil::key_value_hash_to_ruby_hash(row_hash);
99
+ }
100
+
101
+ struct FindCallbackArgs
102
+ {
103
+ std::string id;
104
+ t_key_value_hash row_content;
105
+
106
+ t_key_value_hash search_keys;
107
+ };
108
+ static bool callback_func__find(const std::string& id, const t_key_value_hash& row_content, void* args)
109
+ {
110
+ FindCallbackArgs* pargs = (FindCallbackArgs*)(args);
111
+ for (t_key_value_hash::const_iterator iter = pargs->search_keys.begin();
112
+ iter != pargs->search_keys.end(); ++iter)
113
+ {
114
+ const std::string& search_key = iter->first;
115
+ const std::string& search_value = iter->second;
116
+
117
+ t_key_value_hash::const_iterator row_content_iter = row_content.find(search_key);
118
+
119
+ // compare nil value. -- s.find({a: '3', b: nil}) when compile b: nil
120
+ if (search_value == MatxRow::null_string)
121
+ {
122
+ if (row_content_iter != row_content.end() && row_content_iter->second != search_value)
123
+ return GMatx::t_continue;
124
+ continue;
125
+ }
126
+
127
+ // compare value not nil
128
+ if (row_content_iter == row_content.end() || row_content_iter->second != search_value)
129
+ return GMatx::t_continue;
130
+ }
131
+ pargs->id = id;
132
+ pargs->row_content = row_content;
133
+ return GMatx::t_break;
127
134
  }
128
135
 
129
- static void callback_func__each(const std::string& key, const t_key_value_hash& row_content, void* args)
136
+ static VALUE t_find(VALUE self, VALUE search_keys_ruby_hash)
130
137
  {
131
- rb_yield_values(2, rb_str_new_cstr(key.c_str()), row_hash_to_ruby_hash(row_content));
138
+ Check_Type(search_keys_ruby_hash, T_HASH);
139
+
140
+ struct FindCallbackArgs args;
141
+ args.search_keys = MatxHashUtil::rb_hash_to_key_value_hash(search_keys_ruby_hash);
142
+
143
+ class GMatx* pMatx = NULL;
144
+ Data_Get_Struct(self, class GMatx, pMatx);
145
+ pMatx->each_call(callback_func__find, &args);
146
+ if (args.id.size() > 0)
147
+ {
148
+ VALUE ret_ary = rb_ary_new();
149
+ rb_ary_push(ret_ary, rb_str_new_cstr(args.id.c_str()));
150
+ rb_ary_push(ret_ary, MatxHashUtil::key_value_hash_to_ruby_hash(args.row_content));
151
+ return ret_ary;
152
+ }
153
+ return Qnil;
154
+ }
155
+
156
+
157
+ static bool callback_func__each(const std::string& key, const t_key_value_hash& row_content, void* args)
158
+ {
159
+ rb_yield_values(2, rb_str_new_cstr(key.c_str()), MatxHashUtil::key_value_hash_to_ruby_hash(row_content));
160
+ return GMatx::t_continue;
132
161
  }
133
162
 
134
163
  static VALUE t_each(VALUE self)
@@ -144,10 +173,11 @@ static VALUE t_each(VALUE self)
144
173
  return self;
145
174
  }
146
175
 
147
- static void callback_func__all(const std::string& key, const t_key_value_hash& row_content, void* args)
176
+ static bool callback_func__all(const std::string& key, const t_key_value_hash& row_content, void* args)
148
177
  {
149
178
  VALUE* p_ret_hash = (VALUE*)(args);
150
- rb_hash_aset(*p_ret_hash, rb_str_new_cstr(key.c_str()), row_hash_to_ruby_hash(row_content));
179
+ rb_hash_aset(*p_ret_hash, rb_str_new_cstr(key.c_str()), MatxHashUtil::key_value_hash_to_ruby_hash(row_content));
180
+ return GMatx::t_continue;
151
181
  }
152
182
 
153
183
  static VALUE t_all(VALUE self)
@@ -160,10 +190,11 @@ static VALUE t_all(VALUE self)
160
190
  return ret_hash;
161
191
  }
162
192
 
163
- static void callback_func__ids(const std::string& key, const t_key_value_hash& row_content, void* args)
193
+ static bool callback_func__ids(const std::string& key, const t_key_value_hash& row_content, void* args)
164
194
  {
165
195
  VALUE* p_ret_array = (VALUE*)(args);
166
196
  rb_ary_push(*p_ret_array, rb_str_new_cstr(key.c_str()));
197
+ return GMatx::t_continue;
167
198
  }
168
199
 
169
200
  static VALUE t_ids(VALUE self)
@@ -207,6 +238,21 @@ static VALUE t_size(VALUE self)
207
238
  return INT2NUM(pMatx->size());
208
239
  }
209
240
 
241
+ static VALUE t_first(VALUE self)
242
+ {
243
+ class GMatx* pMatx = NULL;
244
+ Data_Get_Struct(self, class GMatx, pMatx);
245
+
246
+ std::string id;
247
+ t_key_value_hash row_hash = pMatx->first(id);
248
+ if (id.empty())
249
+ return Qnil;
250
+ VALUE ret_array = rb_ary_new();
251
+ rb_ary_push(ret_array, rb_str_new_cstr(id.c_str()));
252
+ rb_ary_push(ret_array, MatxHashUtil::key_value_hash_to_ruby_hash(row_hash));
253
+
254
+ return ret_array;
255
+ }
210
256
 
211
257
  VALUE cSMatrix;
212
258
 
@@ -220,7 +266,9 @@ extern "C" void Init_s_matrix()
220
266
  rb_define_method(cSMatrix, "to_s", (VALUE(*)(ANYARGS))t_to_s, 0);
221
267
  rb_define_method(cSMatrix, "add_row", (VALUE(*)(ANYARGS))t_add_row, 2);
222
268
  rb_define_method(cSMatrix, "get_row", (VALUE(*)(ANYARGS))t_get_row, 1);
269
+ rb_define_method(cSMatrix, "find", (VALUE(*)(ANYARGS))t_find, 1);
223
270
  rb_define_method(cSMatrix, "each", (VALUE(*)(ANYARGS))t_each, 0);
271
+ rb_define_method(cSMatrix, "first", (VALUE(*)(ANYARGS))t_first, 0);
224
272
  rb_define_method(cSMatrix, "all", (VALUE(*)(ANYARGS))t_all, 0);
225
273
  rb_define_method(cSMatrix, "ids", (VALUE(*)(ANYARGS))t_ids, 0);
226
274
  rb_define_method(cSMatrix, "keys", (VALUE(*)(ANYARGS))t_keys, 0);
@@ -1,5 +1,5 @@
1
1
  class SMatrix
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
4
4
 
5
5
  require "s_matrix/s_matrix"
data/spec/smatrix_spec.rb CHANGED
@@ -102,16 +102,19 @@ describe SMatrix do
102
102
  expect(a.all).to eq({})
103
103
  expect(a.ids).to eq([])
104
104
  expect(a.keys).to eq([])
105
+ expect(a.first).to eq(nil)
105
106
 
106
107
  a.add_row('2', {a: 2})
107
108
  expect(a.all).to eq({'2' => {'a' => '2'}})
108
109
  expect(a.ids).to eq(['2'])
109
110
  expect(a.keys).to eq(['a'])
111
+ expect(a.first).to eq(['2', {'a' => '2'}])
110
112
 
111
113
  a.add_row('2', {b: 3})
112
114
  expect(a.all).to eq({'2' => {'a' => nil, 'b' => '3'}})
113
115
  expect(a.ids).to eq(['2'])
114
116
  expect(a.keys).to eq(['a', 'b'])
117
+ expect(a.first).to eq(['2', {'a' => nil, 'b' => '3'}])
115
118
 
116
119
  a.add_row('3', {b: 3})
117
120
  expect(a.all).to eq({
@@ -120,6 +123,29 @@ describe SMatrix do
120
123
  })
121
124
  expect(a.ids).to eq(['2', '3'])
122
125
  expect(a.keys).to eq(['a', 'b'])
126
+ expect(a.first == ['2', {'a' => nil, 'b' => '3'}] || a.first == ['3', {'b' => '3'}]).to eq(true)
127
+ end
128
+ end
129
+
130
+ describe 'find' do
131
+ it '' do
132
+ a = SMatrix.new
133
+ expect( a.find({a: '2'}) ).to eq nil
134
+
135
+ a.add_row('223', {a: 2})
136
+ expect( a.find({a: '2'}) ).to eq ['223', {'a' => '2'}]
137
+
138
+ a.add_row('224', {a: 3})
139
+ expect( a.find({a: '2'}) ).to eq ['223', {'a' => '2'}]
140
+ expect( a.find({a: '3'}) ).to eq ['224', {'a' => '3'}]
141
+ expect( a.find({a: '3', b: nil}) ).to eq ['224', {'a' => '3'}]
142
+
143
+ a.add_row('225', {a: 2, b: 3})
144
+ expect( a.find({a: '2'})[0] == '223' || a.find({a: '2'})[0] == '224' ).to eq true
145
+ expect( a.find({b: '3'}) ).to eq ['225', {'a' => '2', 'b' => '3'}]
146
+ expect( a.find({a: '2', b: '3'}) ).to eq ['225', {'a' => '2', 'b' => '3'}]
147
+ expect( a.find({a: '2', b: '1'}) ).to eq nil
148
+ expect( a.find({a: nil, b: '3'}) ).to eq nil
123
149
  end
124
150
  end
125
151
 
data/todolist.txt CHANGED
@@ -1,16 +1,15 @@
1
1
  todolist:
2
2
 
3
3
  1. function with first priority:
4
- -done all
5
- -return {'23423' => {'name' => 'haha', 'hp' => '23425'}, '234232' => {} }
6
- -done ids
7
- -return ['233423', '234134']
8
- keys
9
- -return ['name', 'hp']
10
- first
4
+ -done all -return {'23423' => {'name' => 'haha', 'hp' => '23425'}, '234232' => {} }
5
+ -done ids -return ['233423', '234134']
6
+ -done keys -return ['name', 'hp']
7
+ -done first -return: ['23423', {'name' => 'haha', 'hp' => '23425'}]
8
+
11
9
  empty?
12
10
  include? {|k, v| k == '2323232'}
13
- find_by name: 'haha', hp: '2342'
11
+ -done find name: 'haha', hp: '2342' -return ['234232', {'name' => 'haha', 'hp' => '23425'}]
12
+ find_all name: 'haha', hp: '2342' -return [['234232', {'name' => 'haha', 'hp' => '23425'}], [], ...]
14
13
  select {|k, v| k == '2232'}
15
14
  merge
16
15
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s_matrix
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - zhangyuan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-19 00:00:00.000000000 Z
11
+ date: 2014-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -102,6 +102,8 @@ files:
102
102
  - ext/s_matrix/gmatx.h
103
103
  - ext/s_matrix/matx_content.cpp
104
104
  - ext/s_matrix/matx_content.h
105
+ - ext/s_matrix/matx_hash_util.cpp
106
+ - ext/s_matrix/matx_hash_util.h
105
107
  - ext/s_matrix/matx_row.cpp
106
108
  - ext/s_matrix/matx_row.h
107
109
  - ext/s_matrix/matx_string.h