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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/Rakefile +11 -1
  4. data/lib/trace_visualization/assert.rb +5 -0
  5. data/lib/trace_visualization/data/lexeme.rb +59 -0
  6. data/lib/trace_visualization/lexeme_overlap_filter.rb +64 -0
  7. data/lib/trace_visualization/mapping.rb +219 -56
  8. data/lib/trace_visualization/preprocessor/Makefile +43 -0
  9. data/lib/trace_visualization/preprocessor/hashmap.c +93 -0
  10. data/lib/trace_visualization/preprocessor/hashmap.h +27 -0
  11. data/lib/trace_visualization/preprocessor/hashmap_test.cpp +90 -0
  12. data/lib/trace_visualization/preprocessor/lexeme.h +11 -0
  13. data/lib/trace_visualization/preprocessor/lexeme_table.c +50 -0
  14. data/lib/trace_visualization/preprocessor/lexeme_table.h +13 -0
  15. data/lib/trace_visualization/preprocessor/lexeme_table_cpp.h +61 -0
  16. data/lib/trace_visualization/preprocessor/parser_functions.c +42 -0
  17. data/lib/trace_visualization/preprocessor/parser_test.cpp +71 -0
  18. data/lib/trace_visualization/preprocessor/preprocessor.l +18 -0
  19. data/lib/trace_visualization/preprocessor/test_main.cpp +39 -0
  20. data/lib/trace_visualization/profile.rb +38 -0
  21. data/lib/trace_visualization/reorder.rb +22 -11
  22. data/lib/trace_visualization/repetitions_psy.rb +1 -1
  23. data/lib/trace_visualization/suffix_array.rb +4 -0
  24. data/lib/trace_visualization/utils.rb +38 -0
  25. data/lib/trace_visualization/version.rb +1 -1
  26. data/lib/trace_visualization/visualization/console_color_print.rb +4 -2
  27. data/lib/trace_visualization.rb +68 -4
  28. data/spec/bwt_spec.rb +29 -7
  29. data/spec/lexeme_overlap_filter_spec.rb +59 -0
  30. data/spec/longest_common_prefix_spec.rb +3 -3
  31. data/spec/mapping_spec.rb +80 -34
  32. data/spec/reorder_spec.rb +25 -7
  33. data/spec/repetitions_psy_spec.rb +5 -5
  34. data/spec/suffix_array_spec.rb +30 -8
  35. data/spec/utils_spec.rb +30 -0
  36. metadata +22 -3
  37. data/LICENSE.txt +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f106c8e07d09c745ae16a15ed0e3b96b932e2424
4
- data.tar.gz: 1c0d4dcd86297c71fe3028c0db5db7a959cd7e38
3
+ metadata.gz: a5779b63579f93699f091c22ada7121df9469fc7
4
+ data.tar.gz: 336cfdc696d598e2247d09b089ec2b426df18e58
5
5
  SHA512:
6
- metadata.gz: 4e15434bcc8cfb6a9546d039ecd5d5b5e2030d5b315eadeec2a8e39e27c832f3362c540bb7e1c9b9d3e9df48400bc9021560cc96353389de45d64041d2bdfc29
7
- data.tar.gz: c322d0e30da40e0dec6d987d3dddef2ba95aa7497a2e3cbaa252197b07bdc7a6721a074888d18d9822579a582cb97cc662b4bdb2fbd6015af9c273ad223ca3e2
6
+ metadata.gz: 583564ac99432f9a0b05e1a51550497ae2f18d30fad51a7443fd8f9e6930567a66cac481a48c9cd594483a35eccdb4eff852a644bc8ce896fe7bffa14c3562fa
7
+ data.tar.gz: 721cf7cdf88fe2ac0380f4eb9517ffda3e6846cba7d317e6c5f1cdfac453c288b40b2b7d674de2039a0a2e88aab0a2b33b89dcde0d379a3b0c674b59fb5bb688
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- ruby "2.0.0"
3
+ ruby '2.0.0'
4
4
 
5
5
  # Specify your gem's dependencies in trace_visualization.gemspec
6
6
  gemspec
7
+
data/Rakefile CHANGED
@@ -1 +1,11 @@
1
- require "bundler/gem_tasks"
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,5 @@
1
+ module TraceVisualization
2
+ def self.assert_instance_of(object, expected_class)
3
+ raise "Illegal parameter type: expected #{expected_class}, actual #{object.class}. Object: #{object}" if not object.instance_of? expected_class
4
+ end
5
+ 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
- module TraceVisualization
2
- module Mapping
3
- require 'time'
4
- require 'ipaddr'
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
- require 'trace_visualization/reorder'
8
+ module TraceVisualization
9
+ class Mapping
7
10
 
8
- PATTERNS = {
11
+ attr_accessor :tokens
12
+
13
+ LEXEME_REGEXP = /\{LEXEME;(?<name>[a-zA-Z0-9]+);(?<source>[^;]+);(?<value>[0-9]+)\}/
9
14
 
10
- "id" => [
11
- /(?<value>\[\d{3,}\])/
15
+ DEFAULT_TOKENS = {
16
+ :ID => [
17
+ /(?<lexeme>\[\d{3,}\])/,
18
+ lambda { |source| source[1 ... -1].to_i }
12
19
  ],
13
-
14
- "ip" => [
15
- /(?<value>(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]?))/
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
- "time" => [
19
- /(?<value>\[\d{2} [a-zA-Z]{3} \d{4} \d{2}\:\d{2}\:\d{2}\])/
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
- class Item
25
- include Comparable
26
-
27
- attr_reader :value # integer value for comparison
28
- attr_reader :src # source value
29
- attr_reader :type # source type
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
- attr_accessor :ord # re-order value
32
-
33
- def initialize(src, type)
34
- @src = src
35
- @type = type
36
-
37
- case type
38
- when "id"
39
- @value = @src[1 ... -1].to_i
40
- when "ip"
41
- @value = IPAddr.new(src).to_i
42
- when "time"
43
- @value = Time.parse(@src[1 ... -1]).to_i
44
- when "char"
45
- @value = src.getbyte(0)
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
- raise Exception.new("unknown type")
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
- def length
52
- @src.length
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
- def <=>(anOther)
56
- @ord <=> anOther.ord
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
- def to_str
60
- @src
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 self.parse(str)
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
- PATTERNS.each do |type, patterns|
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 += item.length
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 self.match(str, type, pattern, map, ppos, itemByPos)
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