kanayago 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +15 -0
  3. data/.rubocop_todo.yml +23 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +79 -0
  6. data/Rakefile +182 -0
  7. data/ext/kanayago/ccan/check_type/check_type.h +63 -0
  8. data/ext/kanayago/ccan/container_of/container_of.h +142 -0
  9. data/ext/kanayago/ccan/list/list.h +791 -0
  10. data/ext/kanayago/ccan/str/str.h +17 -0
  11. data/ext/kanayago/constant.h +53 -0
  12. data/ext/kanayago/extconf.rb +21 -0
  13. data/ext/kanayago/id.h +347 -0
  14. data/ext/kanayago/id_table.h +39 -0
  15. data/ext/kanayago/internal/array.h +151 -0
  16. data/ext/kanayago/internal/basic_operators.h +64 -0
  17. data/ext/kanayago/internal/bignum.h +244 -0
  18. data/ext/kanayago/internal/bits.h +568 -0
  19. data/ext/kanayago/internal/compile.h +34 -0
  20. data/ext/kanayago/internal/compilers.h +107 -0
  21. data/ext/kanayago/internal/complex.h +29 -0
  22. data/ext/kanayago/internal/encoding.h +36 -0
  23. data/ext/kanayago/internal/error.h +218 -0
  24. data/ext/kanayago/internal/fixnum.h +184 -0
  25. data/ext/kanayago/internal/gc.h +322 -0
  26. data/ext/kanayago/internal/hash.h +191 -0
  27. data/ext/kanayago/internal/imemo.h +261 -0
  28. data/ext/kanayago/internal/io.h +140 -0
  29. data/ext/kanayago/internal/numeric.h +274 -0
  30. data/ext/kanayago/internal/parse.h +117 -0
  31. data/ext/kanayago/internal/rational.h +71 -0
  32. data/ext/kanayago/internal/re.h +28 -0
  33. data/ext/kanayago/internal/ruby_parser.h +125 -0
  34. data/ext/kanayago/internal/sanitizers.h +297 -0
  35. data/ext/kanayago/internal/serial.h +23 -0
  36. data/ext/kanayago/internal/static_assert.h +16 -0
  37. data/ext/kanayago/internal/string.h +186 -0
  38. data/ext/kanayago/internal/symbol.h +45 -0
  39. data/ext/kanayago/internal/thread.h +79 -0
  40. data/ext/kanayago/internal/variable.h +72 -0
  41. data/ext/kanayago/internal/vm.h +137 -0
  42. data/ext/kanayago/internal/warnings.h +16 -0
  43. data/ext/kanayago/internal.h +108 -0
  44. data/ext/kanayago/kanayago.c +420 -0
  45. data/ext/kanayago/kanayago.h +21 -0
  46. data/ext/kanayago/lex.c +302 -0
  47. data/ext/kanayago/method.h +255 -0
  48. data/ext/kanayago/node.c +440 -0
  49. data/ext/kanayago/node.h +111 -0
  50. data/ext/kanayago/node_name.inc +224 -0
  51. data/ext/kanayago/parse.c +26931 -0
  52. data/ext/kanayago/parse.h +244 -0
  53. data/ext/kanayago/parse.tmp.y +16145 -0
  54. data/ext/kanayago/parser_bits.h +564 -0
  55. data/ext/kanayago/parser_node.h +32 -0
  56. data/ext/kanayago/parser_st.c +164 -0
  57. data/ext/kanayago/parser_st.h +162 -0
  58. data/ext/kanayago/parser_value.h +106 -0
  59. data/ext/kanayago/probes.h +4 -0
  60. data/ext/kanayago/ruby_assert.h +14 -0
  61. data/ext/kanayago/ruby_atomic.h +23 -0
  62. data/ext/kanayago/ruby_parser.c +1165 -0
  63. data/ext/kanayago/rubyparser.h +1391 -0
  64. data/ext/kanayago/shape.h +234 -0
  65. data/ext/kanayago/st.c +2339 -0
  66. data/ext/kanayago/symbol.h +123 -0
  67. data/ext/kanayago/thread_pthread.h +168 -0
  68. data/ext/kanayago/universal_parser.c +230 -0
  69. data/ext/kanayago/vm_core.h +2215 -0
  70. data/ext/kanayago/vm_opts.h +67 -0
  71. data/lib/kanayago/version.rb +5 -0
  72. data/lib/kanayago.rb +11 -0
  73. data/sig/kanayago.rbs +4 -0
  74. metadata +116 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7dc8924bd1972c79a19ec99a5317d3805ec71536f4f53e11ee12e11930c16af2
4
+ data.tar.gz: a7ef01c1049b9e4132299b21a58b37ecd61fd18813f5f9208a02f6950d3b46fa
5
+ SHA512:
6
+ metadata.gz: 29da7596273da188566563726bd3cd26fde141ec06c30cad03ddc0b52ccc7083815c125425d011a14e253fc070fecf71831d56523064f8fbfbc9bca3fc3d7da2
7
+ data.tar.gz: 03c77678bee8697c788a9ef5d7f9e65db5014608ba41f0d9e2223f1b1cfd96195aa8379d05482a404deeaa9d9b17dd72c3f015cf889b9f74b8e29255e356e8d1
data/.rubocop.yml ADDED
@@ -0,0 +1,15 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ Metrics/BlockLength:
4
+ Exclude:
5
+ - Rakefile
6
+ - kanayago.gemspec
7
+
8
+ RBS:
9
+ Enabled: true
10
+
11
+ require:
12
+ - rubocop-minitest
13
+ - rubocop-on-rbs
14
+ - rubocop-rake
15
+
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,23 @@
1
+ # Offense count: 4
2
+ # Configuration parameters: CountComments, CountAsOne.
3
+ Metrics/ClassLength:
4
+ Max: 318
5
+
6
+ # Offense count: 40
7
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
8
+ Metrics/MethodLength:
9
+ Max: 49
10
+
11
+ # Offense count: 2
12
+ # Configuration parameters: AllowedConstants.
13
+ Style/Documentation:
14
+ Exclude:
15
+ - 'spec/**/*'
16
+ - 'test/**/*'
17
+
18
+ # Offense count: 4
19
+ # Configuration parameters: AllowedVariables.
20
+ Style/GlobalVars:
21
+ Exclude:
22
+ - 'ext/kanayago/extconf.rb'
23
+
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 S-H-GAMELINKS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Kanayago
2
+
3
+ Trying to Make Ruby's Parser Available as a Gem.
4
+
5
+ ## Installation
6
+
7
+ First, install Ruby master with Universal Parser.
8
+
9
+ ```console
10
+ RUBY_CONFIGURE_OPTS="cppflags=-DUNIVERSAL_PARSER" rbenv install ruby-dev
11
+ ```
12
+
13
+ Clone this repository.
14
+
15
+ ```console
16
+ git clone https://github.com/S-H-GAMELINKS/kanayago.git
17
+ ```
18
+
19
+ Move `kanayago` directory, and run `bundle install`.
20
+
21
+ ```console
22
+ cd kanayago && bundle install
23
+ ```
24
+
25
+ Finally, build `Kanayago` gem and install it.
26
+
27
+ ```console
28
+ bundle exec rake build
29
+ gem install pkg/kanayago-0.1.0.gem
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```ruby
35
+ require 'kanayago/kanayago'
36
+
37
+ result = Kanayago.parse('117 + 117')
38
+
39
+ p result
40
+ # =>
41
+ #{
42
+ # "NODE_SCOPE" => {
43
+ # "args" => nil,
44
+ # "body" => {
45
+ # "NODE_OPCALL" => {
46
+ # "recv" => {
47
+ # "NODE_INTEGER" => 117
48
+ # },
49
+ # "mid" => :+,
50
+ # "args" => {
51
+ # "NODE_LIST" => [
52
+ # {
53
+ # "NODE_INTEGER"=>117
54
+ # }
55
+ # ]
56
+ # }
57
+ # }
58
+ # }
59
+ # }
60
+ #}
61
+ ```
62
+
63
+ ## Development
64
+
65
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
66
+
67
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
68
+
69
+ ## Contributing
70
+
71
+ Bug reports and pull requests are welcome on GitHub at https://github.com/S-H-GAMELINKS/kanayago.
72
+
73
+ ## Referenced implementations
74
+
75
+ [yui-knk/ruby-parser](https://github.com/yui-knk/ruby-parser)
76
+
77
+ ## License
78
+
79
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/extensiontask'
5
+ require 'rake/testtask'
6
+ require 'test_queue'
7
+ require 'test_queue/runner/minitest'
8
+ require 'fileutils'
9
+
10
+ COPY_TARGETS = %w[
11
+ ccan/check_type/check_type.h
12
+ ccan/container_of/container_of.h
13
+ ccan/list/list.h
14
+ ccan/str/str.h
15
+ constant.h
16
+ id_table.h
17
+ internal/array.h
18
+ internal/basic_operators.h
19
+ internal/bignum.h
20
+ internal/bits.h
21
+ internal/compile.h
22
+ internal/compilers.h
23
+ internal/complex.h
24
+ internal/encoding.h
25
+ internal/error.h
26
+ internal/fixnum.h
27
+ internal/gc.h
28
+ internal/hash.h
29
+ internal/imemo.h
30
+ internal/io.h
31
+ internal/numeric.h
32
+ internal/parse.h
33
+ internal/rational.h
34
+ internal/re.h
35
+ internal/ruby_parser.h
36
+ internal/sanitizers.h
37
+ internal/serial.h
38
+ internal/static_assert.h
39
+ internal/string.h
40
+ internal/symbol.h
41
+ internal/thread.h
42
+ internal/variable.h
43
+ internal/warnings.h
44
+ internal/vm.h
45
+ internal.h
46
+ method.h
47
+ node.c
48
+ node.h
49
+ parse.y
50
+ parser_bits.h
51
+ parser_node.h
52
+ parser_st.c
53
+ parser_st.h
54
+ parser_value.h
55
+ ruby_assert.h
56
+ ruby_atomic.h
57
+ ruby_parser.c
58
+ rubyparser.h
59
+ shape.h
60
+ st.c
61
+ symbol.h
62
+ thread_pthread.h
63
+ universal_parser.c
64
+ vm_core.h
65
+ vm_opts.h
66
+ ].freeze
67
+
68
+ namespace :ruby_parser do
69
+ desc 'import ruby parser files'
70
+ task :import do
71
+ `git clone https://github.com/ruby/ruby.git tmp/ruby --depth=1`
72
+
73
+ dist = File.expand_path('ext/kanayago', __dir__)
74
+ ruby_dir = File.expand_path('tmp/ruby', __dir__)
75
+
76
+ directories = ['ccan', 'ccan/check_type', 'ccan/container', 'ccan/container_of', 'ccan/list', 'ccan/str',
77
+ 'internal']
78
+
79
+ directories.each do |dir|
80
+ Dir.mkdir File.join(dist, dir)
81
+ end
82
+
83
+ COPY_TARGETS.each do |target|
84
+ FileUtils.cp File.join(ruby_dir, target), File.join(dist, target)
85
+ end
86
+
87
+ # "parse.tmp.y"
88
+ id2token_path = File.join(ruby_dir, 'tool/id2token.rb')
89
+ parse_y_path = File.join(dist, 'parse.y')
90
+ parse_tmp_y_path = File.join(dist, 'parse.tmp.y')
91
+ sh "ruby #{id2token_path} #{parse_y_path} > #{parse_tmp_y_path}"
92
+
93
+ # "id.h"
94
+ generic_erb_path = File.join(ruby_dir, 'tool/generic_erb.rb')
95
+ id_h_tmpl_path = File.join(ruby_dir, 'template/id.h.tmpl')
96
+ id_h_path = File.join(dist, 'id.h')
97
+ sh "ruby #{generic_erb_path} --output=#{id_h_path} #{id_h_tmpl_path}"
98
+
99
+ # "probes.h"
100
+ probes_h_path = File.join(dist, 'probes.h')
101
+ File.open(probes_h_path, 'w+') do |f|
102
+ f << <<~SRC
103
+ #define RUBY_DTRACE_PARSE_BEGIN_ENABLED() (0)
104
+ #define RUBY_DTRACE_PARSE_BEGIN(arg0, arg1) (void)(arg0), (void)(arg1);
105
+ #define RUBY_DTRACE_PARSE_END_ENABLED() (0)
106
+ #define RUBY_DTRACE_PARSE_END(arg0, arg1) (void)(arg0), (void)(arg1);
107
+ SRC
108
+ end
109
+
110
+ # "node_name.inc"
111
+ node_name_path = File.join(ruby_dir, 'tool/node_name.rb')
112
+ rubyparser_h_path = File.join(dist, 'rubyparser.h')
113
+ node_name_inc_path = File.join(dist, 'node_name.inc')
114
+ sh "ruby -n #{node_name_path} < #{rubyparser_h_path} > #{node_name_inc_path}"
115
+
116
+ # "lex.c"
117
+ sh 'cd tmp/ruby && ./autogen.sh && ./configure && make'
118
+ FileUtils.mv File.join(ruby_dir, 'lex.c'), File.join(dist, 'lex.c')
119
+
120
+ `rm -rf tmp/ruby`
121
+ end
122
+
123
+ desc 'build ruby parse.c and parse.h with lrama'
124
+ task :build do
125
+ sh 'bundle exec lrama -oext/kanayago/parse.c -Hext/kanayago/parse.h ext/kanayago/parse.tmp.y'
126
+ end
127
+
128
+ desc 'clean to ruby parser file'
129
+ task :clean do
130
+ dist = File.expand_path('./ext/kanayago')
131
+
132
+ COPY_TARGETS.each do |target|
133
+ FileUtils.rm File.join(dist, target), force: true
134
+ end
135
+ delete_files = ['constant.h', 'id.h', 'id.h', 'id.h', 'id_table.h', 'lex.c', 'node_name.inc', 'parse.c', 'parse.h',
136
+ 'parse.y', 'parse.tmp.y', 'probes.h', 'shape.h']
137
+
138
+ delete_files.each do |file|
139
+ FileUtils.rm File.join(dist, file), force: true
140
+ end
141
+
142
+ delete_directories = %w[ccan internal]
143
+
144
+ delete_directories.each do |dir|
145
+ FileUtils.rm_rf File.join(dist, dir)
146
+ end
147
+ end
148
+ end
149
+
150
+ task build: ['ruby_parser:build', 'compile']
151
+ task install: ['ruby_parser:build', 'compile']
152
+
153
+ GEMSPEC = Gem::Specification.load('kanayago.gemspec')
154
+
155
+ Rake::ExtensionTask.new('kanayago', GEMSPEC) do |ext|
156
+ ext.lib_dir = 'lib/kanayago'
157
+ end
158
+
159
+ namespace :queue do
160
+ desc 'run test with test-queue'
161
+ task :test do
162
+ sh 'bundle exec minitest-queue $(find test/ -name \*_test.rb)'
163
+ end
164
+ end
165
+
166
+ Rake::TestTask.new(:test) do |t|
167
+ t.libs << 'test'
168
+ t.libs << 'lib'
169
+ t.test_files = FileList['test/**/*_test.rb']
170
+ end
171
+
172
+ desc 'try to kanayago code'
173
+ task :run do
174
+ sh 'ruby test.rb'
175
+ end
176
+
177
+ desc 'debug to kanayago code in gdb'
178
+ task :gdb do
179
+ sh 'bundle exec gdb --args ruby test.rb'
180
+ end
181
+
182
+ task default: %i[clobber compile]
@@ -0,0 +1,63 @@
1
+ /* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
2
+ #ifndef CCAN_CHECK_TYPE_H
3
+ #define CCAN_CHECK_TYPE_H
4
+
5
+ /**
6
+ * ccan_check_type - issue a warning or build failure if type is not correct.
7
+ * @expr: the expression whose type we should check (not evaluated).
8
+ * @type: the exact type we expect the expression to be.
9
+ *
10
+ * This macro is usually used within other macros to try to ensure that a macro
11
+ * argument is of the expected type. No type promotion of the expression is
12
+ * done: an unsigned int is not the same as an int!
13
+ *
14
+ * ccan_check_type() always evaluates to 0.
15
+ *
16
+ * If your compiler does not support typeof, then the best we can do is fail
17
+ * to compile if the sizes of the types are unequal (a less complete check).
18
+ *
19
+ * Example:
20
+ * // They should always pass a 64-bit value to _set_some_value!
21
+ * #define set_some_value(expr) \
22
+ * _set_some_value((ccan_check_type((expr), uint64_t), (expr)))
23
+ */
24
+
25
+ /**
26
+ * ccan_check_types_match - issue a warning or build failure if types are not same.
27
+ * @expr1: the first expression (not evaluated).
28
+ * @expr2: the second expression (not evaluated).
29
+ *
30
+ * This macro is usually used within other macros to try to ensure that
31
+ * arguments are of identical types. No type promotion of the expressions is
32
+ * done: an unsigned int is not the same as an int!
33
+ *
34
+ * ccan_check_types_match() always evaluates to 0.
35
+ *
36
+ * If your compiler does not support typeof, then the best we can do is fail
37
+ * to compile if the sizes of the types are unequal (a less complete check).
38
+ *
39
+ * Example:
40
+ * // Do subtraction to get to enclosing type, but make sure that
41
+ * // pointer is of correct type for that member.
42
+ * #define ccan_container_of(mbr_ptr, encl_type, mbr) \
43
+ * (ccan_check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
44
+ * ((encl_type *) \
45
+ * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
46
+ */
47
+ #if defined(HAVE_TYPEOF) && HAVE_TYPEOF
48
+ #define ccan_check_type(expr, type) \
49
+ ((typeof(expr) *)0 != (type *)0)
50
+
51
+ #define ccan_check_types_match(expr1, expr2) \
52
+ ((typeof(expr1) *)0 != (typeof(expr2) *)0)
53
+ #else
54
+ #include "ccan/build_assert/build_assert.h"
55
+ /* Without typeof, we can only test the sizes. */
56
+ #define ccan_check_type(expr, type) \
57
+ CCAN_BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
58
+
59
+ #define ccan_check_types_match(expr1, expr2) \
60
+ CCAN_BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
61
+ #endif /* HAVE_TYPEOF */
62
+
63
+ #endif /* CCAN_CHECK_TYPE_H */
@@ -0,0 +1,142 @@
1
+ /* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
2
+ #ifndef CCAN_CONTAINER_OF_H
3
+ #define CCAN_CONTAINER_OF_H
4
+ #include "ccan/check_type/check_type.h"
5
+
6
+ /**
7
+ * ccan_container_of - get pointer to enclosing structure
8
+ * @member_ptr: pointer to the structure member
9
+ * @containing_type: the type this member is within
10
+ * @member: the name of this member within the structure.
11
+ *
12
+ * Given a pointer to a member of a structure, this macro does pointer
13
+ * subtraction to return the pointer to the enclosing type.
14
+ *
15
+ * Example:
16
+ * struct foo {
17
+ * int fielda, fieldb;
18
+ * // ...
19
+ * };
20
+ * struct info {
21
+ * int some_other_field;
22
+ * struct foo my_foo;
23
+ * };
24
+ *
25
+ * static struct info *foo_to_info(struct foo *foo)
26
+ * {
27
+ * return ccan_container_of(foo, struct info, my_foo);
28
+ * }
29
+ */
30
+ #define ccan_container_of(member_ptr, containing_type, member) \
31
+ ((containing_type *) \
32
+ ((char *)(member_ptr) \
33
+ - ccan_container_off(containing_type, member)) \
34
+ + ccan_check_types_match(*(member_ptr), ((containing_type *)0)->member))
35
+
36
+
37
+ /**
38
+ * ccan_container_of_or_null - get pointer to enclosing structure, or NULL
39
+ * @member_ptr: pointer to the structure member
40
+ * @containing_type: the type this member is within
41
+ * @member: the name of this member within the structure.
42
+ *
43
+ * Given a pointer to a member of a structure, this macro does pointer
44
+ * subtraction to return the pointer to the enclosing type, unless it
45
+ * is given NULL, in which case it also returns NULL.
46
+ *
47
+ * Example:
48
+ * struct foo {
49
+ * int fielda, fieldb;
50
+ * // ...
51
+ * };
52
+ * struct info {
53
+ * int some_other_field;
54
+ * struct foo my_foo;
55
+ * };
56
+ *
57
+ * static struct info *foo_to_info_allowing_null(struct foo *foo)
58
+ * {
59
+ * return ccan_container_of_or_null(foo, struct info, my_foo);
60
+ * }
61
+ */
62
+ static inline char *container_of_or_null_(void *member_ptr, size_t offset)
63
+ {
64
+ return member_ptr ? (char *)member_ptr - offset : NULL;
65
+ }
66
+ #define ccan_container_of_or_null(member_ptr, containing_type, member) \
67
+ ((containing_type *) \
68
+ ccan_container_of_or_null_(member_ptr, \
69
+ ccan_container_off(containing_type, member)) \
70
+ + ccan_check_types_match(*(member_ptr), ((containing_type *)0)->member))
71
+
72
+ /**
73
+ * ccan_container_off - get offset to enclosing structure
74
+ * @containing_type: the type this member is within
75
+ * @member: the name of this member within the structure.
76
+ *
77
+ * Given a pointer to a member of a structure, this macro does
78
+ * typechecking and figures out the offset to the enclosing type.
79
+ *
80
+ * Example:
81
+ * struct foo {
82
+ * int fielda, fieldb;
83
+ * // ...
84
+ * };
85
+ * struct info {
86
+ * int some_other_field;
87
+ * struct foo my_foo;
88
+ * };
89
+ *
90
+ * static struct info *foo_to_info(struct foo *foo)
91
+ * {
92
+ * size_t off = ccan_container_off(struct info, my_foo);
93
+ * return (void *)((char *)foo - off);
94
+ * }
95
+ */
96
+ #define ccan_container_off(containing_type, member) \
97
+ offsetof(containing_type, member)
98
+
99
+ /**
100
+ * ccan_container_of_var - get pointer to enclosing structure using a variable
101
+ * @member_ptr: pointer to the structure member
102
+ * @container_var: a pointer of same type as this member's container
103
+ * @member: the name of this member within the structure.
104
+ *
105
+ * Given a pointer to a member of a structure, this macro does pointer
106
+ * subtraction to return the pointer to the enclosing type.
107
+ *
108
+ * Example:
109
+ * static struct info *foo_to_i(struct foo *foo)
110
+ * {
111
+ * struct info *i = ccan_container_of_var(foo, i, my_foo);
112
+ * return i;
113
+ * }
114
+ */
115
+ #if defined(HAVE_TYPEOF) && HAVE_TYPEOF
116
+ #define ccan_container_of_var(member_ptr, container_var, member) \
117
+ ccan_container_of(member_ptr, typeof(*container_var), member)
118
+ #else
119
+ #define ccan_container_of_var(member_ptr, container_var, member) \
120
+ ((void *)((char *)(member_ptr) - \
121
+ ccan_container_off_var(container_var, member)))
122
+ #endif
123
+
124
+ /**
125
+ * ccan_container_off_var - get offset of a field in enclosing structure
126
+ * @container_var: a pointer to a container structure
127
+ * @member: the name of a member within the structure.
128
+ *
129
+ * Given (any) pointer to a structure and a its member name, this
130
+ * macro does pointer subtraction to return offset of member in a
131
+ * structure memory layout.
132
+ *
133
+ */
134
+ #if defined(HAVE_TYPEOF) && HAVE_TYPEOF
135
+ #define ccan_container_off_var(var, member) \
136
+ ccan_container_off(typeof(*var), member)
137
+ #else
138
+ #define ccan_container_off_var(var, member) \
139
+ ((const char *)&(var)->member - (const char *)(var))
140
+ #endif
141
+
142
+ #endif /* CCAN_CONTAINER_OF_H */