trace_visualization 0.0.1 → 0.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 +4 -4
- data/Gemfile +2 -1
- data/Rakefile +11 -1
- data/lib/trace_visualization/assert.rb +5 -0
- data/lib/trace_visualization/data/lexeme.rb +59 -0
- data/lib/trace_visualization/lexeme_overlap_filter.rb +64 -0
- data/lib/trace_visualization/mapping.rb +219 -56
- data/lib/trace_visualization/preprocessor/Makefile +43 -0
- data/lib/trace_visualization/preprocessor/hashmap.c +93 -0
- data/lib/trace_visualization/preprocessor/hashmap.h +27 -0
- data/lib/trace_visualization/preprocessor/hashmap_test.cpp +90 -0
- data/lib/trace_visualization/preprocessor/lexeme.h +11 -0
- data/lib/trace_visualization/preprocessor/lexeme_table.c +50 -0
- data/lib/trace_visualization/preprocessor/lexeme_table.h +13 -0
- data/lib/trace_visualization/preprocessor/lexeme_table_cpp.h +61 -0
- data/lib/trace_visualization/preprocessor/parser_functions.c +42 -0
- data/lib/trace_visualization/preprocessor/parser_test.cpp +71 -0
- data/lib/trace_visualization/preprocessor/preprocessor.l +18 -0
- data/lib/trace_visualization/preprocessor/test_main.cpp +39 -0
- data/lib/trace_visualization/profile.rb +38 -0
- data/lib/trace_visualization/reorder.rb +22 -11
- data/lib/trace_visualization/repetitions_psy.rb +1 -1
- data/lib/trace_visualization/suffix_array.rb +4 -0
- data/lib/trace_visualization/utils.rb +38 -0
- data/lib/trace_visualization/version.rb +1 -1
- data/lib/trace_visualization/visualization/console_color_print.rb +4 -2
- data/lib/trace_visualization.rb +68 -4
- data/spec/bwt_spec.rb +29 -7
- data/spec/lexeme_overlap_filter_spec.rb +59 -0
- data/spec/longest_common_prefix_spec.rb +3 -3
- data/spec/mapping_spec.rb +80 -34
- data/spec/reorder_spec.rb +25 -7
- data/spec/repetitions_psy_spec.rb +5 -5
- data/spec/suffix_array_spec.rb +30 -8
- data/spec/utils_spec.rb +30 -0
- metadata +22 -3
- data/LICENSE.txt +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5779b63579f93699f091c22ada7121df9469fc7
|
4
|
+
data.tar.gz: 336cfdc696d598e2247d09b089ec2b426df18e58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 583564ac99432f9a0b05e1a51550497ae2f18d30fad51a7443fd8f9e6930567a66cac481a48c9cd594483a35eccdb4eff852a644bc8ce896fe7bffa14c3562fa
|
7
|
+
data.tar.gz: 721cf7cdf88fe2ac0380f4eb9517ffda3e6846cba7d317e6c5f1cdfac453c288b40b2b7d674de2039a0a2e88aab0a2b33b89dcde0d379a3b0c674b59fb5bb688
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
desc 'Compile preprocessor'
|
4
|
+
task :install do
|
5
|
+
system('cd lib/trace_visualization/preprocessor; make install; make clean')
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Spec all functionality of gem'
|
9
|
+
task :spec_all do
|
10
|
+
system('rspec spec/*')
|
11
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module TraceVisualization
|
2
|
+
module Data
|
3
|
+
class Lexeme
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :value
|
6
|
+
attr_accessor :int_value
|
7
|
+
|
8
|
+
# Length of preprocessed string (see LEXEME_REGEXP)
|
9
|
+
attr_accessor :lexeme_length
|
10
|
+
|
11
|
+
attr_accessor :ord
|
12
|
+
|
13
|
+
def initialize(name, value, int_value = -1)
|
14
|
+
@name, @value, @int_value = name, value, int_value
|
15
|
+
end
|
16
|
+
|
17
|
+
def length
|
18
|
+
@value.length
|
19
|
+
end
|
20
|
+
|
21
|
+
def <=>(anOther)
|
22
|
+
@ord <=> anOther.ord
|
23
|
+
end
|
24
|
+
|
25
|
+
def <(other)
|
26
|
+
@ord < other.ord
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_int
|
30
|
+
@ord
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_i
|
34
|
+
to_int
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_str
|
38
|
+
@value
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
to_str
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing(name, *args, &blk)
|
46
|
+
raise "Missing method #{name}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class LexemePos
|
51
|
+
attr_accessor :lexeme
|
52
|
+
attr_accessor :pos
|
53
|
+
|
54
|
+
def initialize(lexeme, pos)
|
55
|
+
@lexeme, @pos = lexeme, pos
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module TraceVisualization
|
2
|
+
module LexemeOverlapFilter
|
3
|
+
|
4
|
+
def self.process(lexeme_poss)
|
5
|
+
lexeme_poss.sort! { |a, b| a.pos <=> b.pos }
|
6
|
+
left_bound = lexeme_poss.inject(0) do |left_bound, lexeme_pos|
|
7
|
+
[lexeme_pos.pos + lexeme_pos.lexeme.length, left_bound].max
|
8
|
+
end
|
9
|
+
|
10
|
+
idx, current, result = 0, [], []
|
11
|
+
|
12
|
+
for pos in 0 .. left_bound
|
13
|
+
|
14
|
+
i = 0
|
15
|
+
while i < current.size
|
16
|
+
lexeme_pos = current[i]
|
17
|
+
|
18
|
+
if lexeme_pos.pos + lexeme_pos.lexeme.length == pos
|
19
|
+
fl_delete_lexeme = false
|
20
|
+
|
21
|
+
if current.size == 1
|
22
|
+
result << lexeme_pos
|
23
|
+
fl_delete_lexeme = true
|
24
|
+
else
|
25
|
+
if is_longest_lexeme(current, lexeme_pos)
|
26
|
+
result << lexeme_pos
|
27
|
+
current = []
|
28
|
+
else
|
29
|
+
fl_delete_lexeme = true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if fl_delete_lexeme
|
34
|
+
current.delete_at(i)
|
35
|
+
i -= 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
i += 1
|
40
|
+
end
|
41
|
+
|
42
|
+
while idx < lexeme_poss.size && lexeme_poss[idx].pos == pos
|
43
|
+
current << lexeme_poss[idx]
|
44
|
+
idx += 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.is_longest_lexeme(lexeme_poss, lexeme_pos)
|
52
|
+
result = true
|
53
|
+
|
54
|
+
lexeme_poss.each do |other_lexeme_pos|
|
55
|
+
if lexeme_pos != other_lexeme_pos && lexeme_pos.lexeme.length < other_lexeme_pos.lexeme.length
|
56
|
+
result = false
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,72 +1,241 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require 'time'
|
2
|
+
require 'ipaddr'
|
3
|
+
|
4
|
+
require 'trace_visualization/reorder'
|
5
|
+
require 'trace_visualization/lexeme_overlap_filter'
|
6
|
+
require 'trace_visualization/data/lexeme'
|
5
7
|
|
6
|
-
|
8
|
+
module TraceVisualization
|
9
|
+
class Mapping
|
7
10
|
|
8
|
-
|
11
|
+
attr_accessor :tokens
|
12
|
+
|
13
|
+
LEXEME_REGEXP = /\{LEXEME;(?<name>[a-zA-Z0-9]+);(?<source>[^;]+);(?<value>[0-9]+)\}/
|
9
14
|
|
10
|
-
|
11
|
-
|
15
|
+
DEFAULT_TOKENS = {
|
16
|
+
:ID => [
|
17
|
+
/(?<lexeme>\[\d{3,}\])/,
|
18
|
+
lambda { |source| source[1 ... -1].to_i }
|
12
19
|
],
|
13
|
-
|
14
|
-
|
15
|
-
/(?<
|
20
|
+
|
21
|
+
:IP => [
|
22
|
+
/(?<lexeme>(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))/,
|
23
|
+
lambda { |source| IPAddr.new(source).to_i }
|
16
24
|
],
|
25
|
+
|
26
|
+
:TIME => [
|
27
|
+
/(?<lexeme>\[\d{2} [a-zA-Z]{3} \d{4} \d{2}\:\d{2}\:\d{2}\])/,
|
28
|
+
lambda { |source| Time.parse(source[1 ... -1]).to_i }
|
29
|
+
]
|
30
|
+
}
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
# hash map: lexeme-object by lexeme-string
|
34
|
+
@lexeme_table = {}
|
35
|
+
|
36
|
+
@tokens = {}
|
37
|
+
@mapped_str = []
|
38
|
+
end
|
17
39
|
|
18
|
-
|
19
|
-
|
20
|
-
|
40
|
+
def self.init(&block)
|
41
|
+
mapping = Mapping.new
|
42
|
+
mapping.instance_eval(&block)
|
43
|
+
mapping
|
44
|
+
end
|
21
45
|
|
22
|
-
|
46
|
+
# new
|
47
|
+
def token(name, pattern, converter_func)
|
48
|
+
@tokens[name] = [pattern, converter_func]
|
49
|
+
end
|
23
50
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
51
|
+
def default_tokens
|
52
|
+
@tokens.merge!(DEFAULT_TOKENS)
|
53
|
+
end
|
54
|
+
|
55
|
+
# new
|
56
|
+
def process(&block)
|
57
|
+
instance_eval(&block)
|
58
|
+
@max_value = TraceVisualization::Reorder.process(@mapped_str)
|
59
|
+
end
|
30
60
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
61
|
+
# Load data from source file. File is read line by line
|
62
|
+
def from_file(path)
|
63
|
+
raise ArgumentError, 'Argument must be a string' unless path.instance_of? String
|
64
|
+
raise ArgumentError, 'File path is not defined' unless path.empty?
|
65
|
+
raise RuntimeError, 'File doesn\'t exists' unless File.exists?(path)
|
66
|
+
|
67
|
+
fd = open(path)
|
68
|
+
process_line(line) while line = fd.gets
|
69
|
+
fd.close
|
70
|
+
end
|
71
|
+
|
72
|
+
# Load data from preprocessed file. File is read line by line
|
73
|
+
def from_preprocessed_file(path)
|
74
|
+
raise ArgumentError, 'Argument must be a string' unless path.instance_of? String
|
75
|
+
raise ArgumentError, 'File path is not defined' unless path.empty?
|
76
|
+
raise RuntimeError, 'File doesn\'t exists' unless File.exists?(path)
|
77
|
+
|
78
|
+
fd = open(path)
|
79
|
+
process_preprocessed_line line while line = fd.gets
|
80
|
+
fd.close
|
81
|
+
end
|
82
|
+
|
83
|
+
# new
|
84
|
+
def from_string(str)
|
85
|
+
raise ArgumentError, 'Argument must be a string' unless str.instance_of? String
|
86
|
+
raise ArgumentError, 'String is not defined' if str.empty?
|
87
|
+
|
88
|
+
@str = str
|
89
|
+
|
90
|
+
str.split("\n").each do |line|
|
91
|
+
process_line(line)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def from_preprocessed_string(str)
|
96
|
+
raise ArgumentError, 'Argument must be a string' if not str.instance_of? String
|
97
|
+
raise ArgumentError, 'String is not defined' if str.empty?
|
98
|
+
|
99
|
+
str.split("\n").each do |line|
|
100
|
+
process_preprocessed_line(line)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_preprocessed_line(line)
|
105
|
+
lexeme_positions = []
|
106
|
+
pos = 0
|
107
|
+
while (m = LEXEME_REGEXP.match(line, pos))
|
108
|
+
pos = m.begin(0)
|
109
|
+
|
110
|
+
lexeme = install_lexeme_m(m)
|
111
|
+
lexeme_positions << TraceVisualization::Data::LexemePos.new(lexeme, pos)
|
112
|
+
|
113
|
+
pos += lexeme.lexeme_length
|
114
|
+
end
|
115
|
+
|
116
|
+
pos, idx = 0, 0
|
117
|
+
while pos < line.length
|
118
|
+
lexeme = nil
|
119
|
+
if idx < lexeme_positions.size && lexeme_positions[idx].pos == pos
|
120
|
+
lexeme = lexeme_positions[idx].lexeme
|
121
|
+
idx += 1
|
46
122
|
else
|
47
|
-
|
123
|
+
lexeme = install_lexeme('CHAR', line[pos], line[pos].ord, 1)
|
48
124
|
end
|
125
|
+
pos += lexeme.lexeme_length
|
126
|
+
@mapped_str << lexeme
|
49
127
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
128
|
+
|
129
|
+
@mapped_str << install_lexeme('CHAR', "\n", "\n".ord, 1)
|
130
|
+
end
|
131
|
+
|
132
|
+
# new
|
133
|
+
def process_line(line)
|
134
|
+
lexeme_poss = []
|
135
|
+
|
136
|
+
@tokens.each do |name, value|
|
137
|
+
pattern, converter_func = value
|
138
|
+
pos = 0
|
139
|
+
while (m = pattern.match(line, pos))
|
140
|
+
lexeme_string, pos = m[:lexeme], m.begin(0)
|
141
|
+
|
142
|
+
lexeme = install_lexeme(name, lexeme_string, converter_func.call(lexeme_string), lexeme_string.length)
|
143
|
+
lexeme_poss << TraceVisualization::Data::LexemePos.new(lexeme, pos)
|
144
|
+
|
145
|
+
pos += lexeme_string.length
|
146
|
+
end
|
53
147
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
148
|
+
|
149
|
+
lexeme_poss = TraceVisualization::LexemeOverlapFilter.process(lexeme_poss)
|
150
|
+
|
151
|
+
pos, idx = 0, 0
|
152
|
+
while pos < line.length
|
153
|
+
lexeme = nil
|
154
|
+
if idx < lexeme_poss.size && lexeme_poss[idx].pos == pos
|
155
|
+
lexeme = lexeme_poss[idx].lexeme
|
156
|
+
idx += 1
|
157
|
+
else
|
158
|
+
lexeme = install_lexeme('CHAR', line[pos], line[pos].ord, 1)
|
159
|
+
end
|
160
|
+
pos += lexeme.length
|
161
|
+
@mapped_str << lexeme
|
57
162
|
end
|
58
163
|
|
59
|
-
|
60
|
-
|
164
|
+
@mapped_str << install_lexeme('CHAR', "\n", "\n".ord, 1)
|
165
|
+
end
|
166
|
+
|
167
|
+
def install_lexeme(name, lexeme_string, int_value, lexeme_length)
|
168
|
+
lexeme = @lexeme_table[lexeme_string]
|
169
|
+
|
170
|
+
if lexeme == nil
|
171
|
+
lexeme = TraceVisualization::Data::Lexeme.new(name, lexeme_string, int_value)
|
172
|
+
lexeme.lexeme_length = lexeme_length
|
173
|
+
@lexeme_table[lexeme_string] = lexeme
|
174
|
+
end
|
175
|
+
|
176
|
+
lexeme
|
177
|
+
end
|
178
|
+
|
179
|
+
def install_lexeme_m(m)
|
180
|
+
lexeme = @lexeme_table[m[:source]]
|
181
|
+
|
182
|
+
if lexeme == nil
|
183
|
+
lexeme = TraceVisualization::Data::Lexeme.new(m[:name], m[:source], m[:value].to_i)
|
184
|
+
lexeme.lexeme_length = m.to_s.length
|
185
|
+
@lexeme_table[m[:source]] = lexeme
|
61
186
|
end
|
187
|
+
|
188
|
+
lexeme
|
189
|
+
end
|
190
|
+
|
191
|
+
def [](index)
|
192
|
+
@mapped_str[index]
|
193
|
+
end
|
194
|
+
|
195
|
+
def length
|
196
|
+
@mapped_str.length
|
197
|
+
end
|
198
|
+
|
199
|
+
def size
|
200
|
+
length
|
201
|
+
end
|
202
|
+
|
203
|
+
def <<(object)
|
204
|
+
@mapped_str << Item.new(object, "unknown")
|
205
|
+
end
|
206
|
+
|
207
|
+
def pop
|
208
|
+
@mapped_str.pop
|
209
|
+
end
|
210
|
+
|
211
|
+
def max
|
212
|
+
@max_value
|
213
|
+
end
|
214
|
+
|
215
|
+
def find_all
|
216
|
+
@mapped_str.find_all { |item| yield(item) }
|
62
217
|
end
|
63
218
|
|
64
|
-
def
|
219
|
+
def restore(pos = 0, length = @mapped_str.length)
|
220
|
+
@mapped_str[pos ... pos + length].inject("") { |res, c| res += c.value }
|
221
|
+
end
|
222
|
+
|
223
|
+
def to_ary
|
224
|
+
@mapped_str.collect { |lexeme| lexeme.value }
|
225
|
+
end
|
226
|
+
|
227
|
+
def method_missing(name, *args, &blk)
|
228
|
+
raise "Missing method #{name}"
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
def parse(str)
|
65
234
|
map = {}
|
66
235
|
ppos = []
|
67
236
|
itemByPos = {}
|
68
237
|
|
69
|
-
|
238
|
+
DEFAULT_TOKENS.each do |type, patterns|
|
70
239
|
patterns.each do |pattern|
|
71
240
|
match(str, type, pattern, map, ppos, itemByPos)
|
72
241
|
end
|
@@ -81,20 +250,19 @@ module TraceVisualization
|
|
81
250
|
if i == ppos[j]
|
82
251
|
item = itemByPos[ppos[j]]
|
83
252
|
result << item
|
84
|
-
i
|
85
|
-
j += 1
|
253
|
+
i, j = i + item.length, j + 1
|
86
254
|
else
|
87
255
|
result << Item.new(str[i], "char")
|
88
256
|
i += 1
|
89
257
|
end
|
90
258
|
end
|
91
259
|
|
92
|
-
TraceVisualization::Reorder.process(result)
|
260
|
+
@max_value = TraceVisualization::Reorder.process(result)
|
93
261
|
|
94
262
|
result
|
95
263
|
end
|
96
264
|
|
97
|
-
def
|
265
|
+
def match(str, type, pattern, map, ppos, itemByPos)
|
98
266
|
pos = 0
|
99
267
|
|
100
268
|
limit = 1000
|
@@ -111,10 +279,5 @@ module TraceVisualization
|
|
111
279
|
end
|
112
280
|
|
113
281
|
end
|
114
|
-
|
115
|
-
def self.restore(array)
|
116
|
-
array.inject("") { |res, c| res += c.to_str }
|
117
|
-
end
|
118
|
-
|
119
282
|
end
|
120
283
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
LEX = flex
|
2
|
+
CC = gcc
|
3
|
+
CPP = g++
|
4
|
+
|
5
|
+
LDFLAGS =-lfl
|
6
|
+
|
7
|
+
CPPUNIT_BIN_CFG = cppunit-config
|
8
|
+
CPPUNIT_CFLAGS = `$(CPPUNIT_BIN_CFG) --cflags`
|
9
|
+
CPPUNIT_LIBS = `$(CPPUNIT_BIN_CFG) --libs`
|
10
|
+
|
11
|
+
CFLAGS =-O0 -Wall -g
|
12
|
+
CPPFLAGS =-O0 -Wall $(CPPUNIT_CFLAGS) -g
|
13
|
+
# CPPFLAGS =-O0 -Wall -std=c++11 $(CPPUNIT_CFLAGS)
|
14
|
+
|
15
|
+
.cpp.o :
|
16
|
+
$(CPP) $(CPPFLAGS) -o $@ -c $<
|
17
|
+
|
18
|
+
.c.o :
|
19
|
+
$(CC) $(CFLAGS) -o $@ -c $<
|
20
|
+
|
21
|
+
%.cppo : %.c
|
22
|
+
$(CPP) $(CPPFLAGS) -o $@ -c $<
|
23
|
+
|
24
|
+
preprocessor: preprocessor.o parser_functions.o
|
25
|
+
$(CC) -o $@ $(LDFLAGS) $^
|
26
|
+
|
27
|
+
preprocessor.c: preprocessor.l
|
28
|
+
$(LEX) -o $@ $^
|
29
|
+
|
30
|
+
unit_tests: test_main.o hashmap.cppo hashmap_test.o \
|
31
|
+
parser_functions.cppo parser_test.o \
|
32
|
+
lexeme_table.cppo
|
33
|
+
$(CPP) -o $@ $(CPPUNIT_LIBS) $^
|
34
|
+
|
35
|
+
unit_tests_run: unit_tests
|
36
|
+
./unit_tests
|
37
|
+
|
38
|
+
install: preprocessor
|
39
|
+
cp preprocessor ../../../bin/
|
40
|
+
make clean
|
41
|
+
|
42
|
+
clean:
|
43
|
+
rm -f *.o *.cppo preprocessor.c unit_tests preprocessor
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#include "hashmap.h"
|
2
|
+
#include <stdio.h>
|
3
|
+
|
4
|
+
hashmap_t* hashmap_new() {
|
5
|
+
hashmap_t* hashmap = (hashmap_t*)malloc(sizeof(hashmap_t));
|
6
|
+
|
7
|
+
hashmap->size = 0;
|
8
|
+
hashmap->table = (hashmap_element**)calloc(HASHMAP_SIZE, sizeof(hashmap_element*));
|
9
|
+
|
10
|
+
return hashmap;
|
11
|
+
}
|
12
|
+
|
13
|
+
void* hashmap_get(hashmap_t* map, long key) {
|
14
|
+
hashmap_element* ptr;
|
15
|
+
int idx = (int)(key % HASHMAP_SIZE);
|
16
|
+
|
17
|
+
for (ptr = map->table[idx]; ptr != NULL; ptr = ptr->next) {
|
18
|
+
if (ptr->key == key) {
|
19
|
+
return ptr->value;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
return NULL;
|
24
|
+
}
|
25
|
+
|
26
|
+
int hashmap_put(hashmap_t* map, long key, void* value) {
|
27
|
+
int result = 1;
|
28
|
+
|
29
|
+
if (hashmap_get(map, key) == NULL) {
|
30
|
+
hashmap_element* ptr;
|
31
|
+
hashmap_element* element = (hashmap_element*) malloc(sizeof(hashmap_element));
|
32
|
+
|
33
|
+
element->key = key;
|
34
|
+
element->value = value;
|
35
|
+
element->next = NULL;
|
36
|
+
|
37
|
+
int idx = (int)(key % HASHMAP_SIZE);
|
38
|
+
ptr = map->table[idx];
|
39
|
+
|
40
|
+
if (ptr) {
|
41
|
+
while (ptr->next) ptr = ptr->next;
|
42
|
+
ptr->next = element;
|
43
|
+
} else {
|
44
|
+
map->table[idx] = element;
|
45
|
+
}
|
46
|
+
|
47
|
+
map->size += 1;
|
48
|
+
|
49
|
+
result = 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
return result;
|
53
|
+
}
|
54
|
+
|
55
|
+
void** hashmap_values(hashmap_t* map) {
|
56
|
+
int i = 0;
|
57
|
+
int j = 0;
|
58
|
+
hashmap_element* ptr;
|
59
|
+
void** values = (void**)malloc(map->size * sizeof(void*));
|
60
|
+
|
61
|
+
for (; i < HASHMAP_SIZE; i += 1) {
|
62
|
+
ptr = map->table[i];
|
63
|
+
|
64
|
+
while (ptr) {
|
65
|
+
values[j] = ptr->value;
|
66
|
+
ptr = ptr->next;
|
67
|
+
j += 1;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
return values;
|
72
|
+
}
|
73
|
+
|
74
|
+
void hashmap_values_free(void** values) {
|
75
|
+
free(values);
|
76
|
+
}
|
77
|
+
|
78
|
+
void hashmap_free(hashmap_t* map) {
|
79
|
+
hashmap_element* ptr;
|
80
|
+
hashmap_element* tmp;
|
81
|
+
int i;
|
82
|
+
for (i = 0; i < HASHMAP_SIZE; i++) {
|
83
|
+
for (ptr = map->table[i]; ptr != NULL; ) {
|
84
|
+
tmp = ptr;
|
85
|
+
ptr = (hashmap_element*)ptr->next;
|
86
|
+
|
87
|
+
free(tmp);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
free(map);
|
91
|
+
}
|
92
|
+
|
93
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#ifndef __HASHMAP_H__
|
2
|
+
#define __HASHMAP_H__
|
3
|
+
|
4
|
+
#include <stdlib.h>
|
5
|
+
|
6
|
+
#define HASHMAP_SIZE (256)
|
7
|
+
|
8
|
+
// typedef struct hashmap_element hashmap_element;
|
9
|
+
struct hashmap_element {
|
10
|
+
long key;
|
11
|
+
void* value;
|
12
|
+
hashmap_element * next;
|
13
|
+
};
|
14
|
+
|
15
|
+
struct hashmap_t {
|
16
|
+
hashmap_element** table;
|
17
|
+
int size;
|
18
|
+
};
|
19
|
+
|
20
|
+
extern hashmap_t* hashmap_new();
|
21
|
+
extern int hashmap_put(hashmap_t* map, long key, void* value);
|
22
|
+
extern void* hashmap_get(hashmap_t* map, long key);
|
23
|
+
extern void** hashmap_values(hashmap_t* map);
|
24
|
+
extern void hashmap_values_free(void** values);
|
25
|
+
extern void hashmap_free(hashmap_t* map);
|
26
|
+
|
27
|
+
#endif
|