ffi-bitmask 0.1.0

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 (5) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/ffi-bitmask.gemspec +14 -0
  4. data/lib/ffi/bitmask.rb +187 -0
  5. metadata +66 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3681418ee2db1b007487476afed2485816a6cc14
4
+ data.tar.gz: 5f298ec2fe516b944cd2bc673d5d25432e15244a
5
+ SHA512:
6
+ metadata.gz: 17e1f79c5d59626aa3c79940934f4faa575944744c0a1ddd215113c660b0ae7cbe09ef669b29dc3a8cf8676ed10a29ce8ea94d269ccf26d40318bcd93b4710b7
7
+ data.tar.gz: 6dc63fc275382adeedb11f46aa70e47b256820d552a237e041e7964fe580909e638550ec6c7dca529fe18485199fe851253eda488ee0d6db6e0978d3d6ef8c49
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017, Brice Videau <brice.videau@imag.fr>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'ffi-bitmask'
3
+ s.version = "0.1.0"
4
+ s.author = "Brice Videau"
5
+ s.email = "brice.videau@imag.fr"
6
+ s.homepage = "https://github.com/Nanosim-LIG/ffi-bitmask"
7
+ s.summary = "bitmask support for ffi"
8
+ s.description = "bitmask support for ffi heavily relying on FFI internals"
9
+ s.files = Dir['ffi-bitmask.gemspec', 'LICENSE', 'lib/**/*']
10
+ s.has_rdoc = true
11
+ s.license = 'BSD-2-Clause'
12
+ s.required_ruby_version = '>= 1.9.3'
13
+ s.add_dependency 'ffi', '~> 1.9', '>=1.9.3'
14
+ end
@@ -0,0 +1,187 @@
1
+ require 'ffi'
2
+
3
+ module FFI
4
+
5
+ module Library
6
+
7
+ # @overload bitmask(name, values)
8
+ # Create a named bitmask
9
+ # @example
10
+ # bitmask :foo, [:red, :green, :blue] # bits 0,1,2 are used
11
+ # bitmask :foo, [:red, :green, 5, :blue] # bits 0,5,6 are used
12
+ # @param [Symbol] name for new bitmask
13
+ # @param [Array<Symbol, Integer>] values for new bitmask
14
+ # @overload bitmask(*args)
15
+ # Create an unamed bitmask
16
+ # @example
17
+ # bm = bitmask :red, :green, :blue # bits 0,1,2 are used
18
+ # bm = bitmask :red, :green, 5, blue # bits 0,5,6 are used
19
+ # @param [Symbol, Integer] args values for new bitmask
20
+ # @overload bitmask(values)
21
+ # Create an unamed bitmask
22
+ # @example
23
+ # bm = bitmask [:red, :green, :blue] # bits 0,1,2 are used
24
+ # bm = bitmask [:red, :green, 5, blue] # bits 0,5,6 are used
25
+ # @param [Array<Symbol, Integer>] values for new bitmask
26
+ # @overload bitmask(native_type, name, values)
27
+ # Create a named enum and specify the native type.
28
+ # @example
29
+ # bitmask FFI::Type::UINT64, :foo, [:red, :green, :blue]
30
+ # @param [FFI::Type] native_type native type for new bitmask
31
+ # @param [Symbol] name for new bitmask
32
+ # @param [Array<Symbol, Integer>] values for new bitmask
33
+ # @overload bitmask(native_type, *args)
34
+ # @example
35
+ # bitmask FFI::Type::UINT64, :red, :green, :blue
36
+ # @param [FFI::Type] native_type native type for new bitmask
37
+ # @param [Symbol, Integer] args values for new bitmask
38
+ # @overload bitmask(native_type, values)
39
+ # Create a named enum and specify the native type.
40
+ # @example
41
+ # bitmask FFI::Type::UINT64, [:red, :green, :blue]
42
+ # @param [FFI::Type] native_type native type for new bitmask
43
+ # @param [Array<Symbol, Integer>] values for new bitmask
44
+ # @return [FFI::Bitmask]
45
+ # Create a new FFI::Bitmask
46
+ def bitmask(*args)
47
+ native_type = args.first.kind_of?(FFI::Type) ? args.shift : nil
48
+ name, values = if args[0].kind_of?(Symbol) && args[1].kind_of?(Array)
49
+ [ args[0], args[1] ]
50
+ elsif args[0].kind_of?(Array)
51
+ [ nil, args[0] ]
52
+ else
53
+ [ nil, args ]
54
+ end
55
+ @ffi_enums = FFI::Enums.new unless defined?(@ffi_enums)
56
+ @ffi_enums << (e = native_type ? FFI::Bitmask.new(native_type, values, name) : FFI::Bitmask.new(values, name))
57
+
58
+ typedef(e, name) if name
59
+ e
60
+ end
61
+
62
+ end
63
+
64
+ # Represents a C enum whose values are power of 2
65
+ #
66
+ # @example
67
+ # enum {
68
+ # red = (1<<0),
69
+ # green = (1<<1),
70
+ # blue = (1<<2)
71
+ # }
72
+ #
73
+ # Contrary to classical enums, bitmask values are usually combined
74
+ # when used.
75
+ class Bitmask < Enum
76
+
77
+ # @overload initialize(info, tag=nil)
78
+ # @param [nil, Enumerable] info symbols and bit rank for new Bitmask
79
+ # @param [nil, Symbol] tag name of new Bitmask
80
+ # @overload initialize(native_type, info, tag=nil)
81
+ # @param [FFI::Type] native_type Native type for new Bitmask
82
+ # @param [nil, Enumerable] info symbols and bit rank for new Bitmask
83
+ # @param [nil, Symbol] tag name of new Bitmask
84
+ def initialize(*args)
85
+ @native_type = args.first.kind_of?(FFI::Type) ? args.shift : Type::INT
86
+ info, @tag = *args
87
+ @kv_map = Hash.new
88
+ unless info.nil?
89
+ last_cst = nil
90
+ value = 0
91
+ info.each do |i|
92
+ case i
93
+ when Symbol
94
+ raise ArgumentError, "duplicate bitmask key" if @kv_map.has_key?(i)
95
+ @kv_map[i] = 1 << value
96
+ last_cst = i
97
+ value += 1
98
+ when Integer
99
+ raise ArgumentError, "bitmask index should be positive" if i<0
100
+ @kv_map[last_cst] = 1 << i
101
+ value = i+1
102
+ end
103
+ end
104
+ end
105
+ @vk_map = @kv_map.invert
106
+ end
107
+
108
+ # Get a symbol list or a value from the bitmask
109
+ # @overload [](*query)
110
+ # Get bitmask value from symbol list
111
+ # @param [Symbol] query
112
+ # @return [Integer]
113
+ # @overload [](query)
114
+ # Get bitmaks value from symbol array
115
+ # @param [Array<Symbol>] query
116
+ # @return [Integer]
117
+ # @overload [](*query)
118
+ # Get a list of bitmask symbols corresponding to
119
+ # the or reduction of a list of integer
120
+ # @param [Integer] query
121
+ # @return [Array<Symbol>]
122
+ # @overload [](query)
123
+ # Get a list of bitmask symbols corresponding to
124
+ # the or reduction of a list of integer
125
+ # @param [Array<Integer>] query
126
+ # @return [Array<Symbol>]
127
+ def [](*query)
128
+ flat_query = query.flatten
129
+ raise ArgumentError, "query should be homogeneous, #{query.inspect}" unless flat_query.all? { |o| o.is_a?(Symbol) } || flat_query.all? { |o| o.is_a?(Integer) || o.respond_to?(:to_int) }
130
+ case flat_query[0]
131
+ when Symbol
132
+ flat_query.inject(0) do |val, o|
133
+ v = @kv_map[o]
134
+ if v then val |= v else val end
135
+ end
136
+ when Integer, ->(o) { o.respond_to?(:to_int) }
137
+ val = flat_query.inject(0) { |mask, o| mask |= o.to_int }
138
+ @kv_map.select { |_, v| v & val != 0 }.keys
139
+ end
140
+ end
141
+
142
+ # Get the native value of a bitmask
143
+ # @overload to_native(query, ctx)
144
+ # @param [Symbol, Integer, #to_int] query
145
+ # @param ctx unused
146
+ # @return [Integer] value of a bitmask
147
+ # @overload to_native(query, ctx)
148
+ # @param [Array<Symbol, Integer, #to_int>] query
149
+ # @param ctx unused
150
+ # @return [Integer] value of a bitmask
151
+ def to_native(query, ctx)
152
+ return 0 if query.nil?
153
+ flat_query = [query].flatten
154
+ flat_query.inject(0) do |val, o|
155
+ case o
156
+ when Symbol
157
+ v = @kv_map[o]
158
+ raise ArgumentError, "invalid bitmask value, #{o.inspect}" unless v
159
+ val |= v
160
+ when Integer
161
+ val |= o
162
+ when ->(obj) { obj.respond_to?(:to_int) }
163
+ val |= o.to_int
164
+ else
165
+ raise ArgumentError, "invalid bitmask value, #{o.inspect}"
166
+ end
167
+ end
168
+ end
169
+
170
+ # @param [Integer] val
171
+ # @param ctx unused
172
+ # @return [Array<Symbol, Integer>] list of symbol names corresponding to val, plus an optional remainder if some bits don't match any constant
173
+ def from_native(val, ctx)
174
+ list = @kv_map.select { |_, v| v & val != 0 }.keys
175
+ # If there are unmatch flags,
176
+ # return them in an integer,
177
+ # else information can be lost.
178
+ # Similar to Enum behavior.
179
+ remainder = val ^ list.inject(0) do |tmp, o|
180
+ v = @kv_map[o]
181
+ if v then tmp |= v else tmp end
182
+ end
183
+ list.push remainder unless remainder == 0
184
+ return list
185
+ end
186
+ end
187
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffi-bitmask
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brice Videau
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.9.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.9'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.9.3
33
+ description: bitmask support for ffi heavily relying on FFI internals
34
+ email: brice.videau@imag.fr
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - LICENSE
40
+ - ffi-bitmask.gemspec
41
+ - lib/ffi/bitmask.rb
42
+ homepage: https://github.com/Nanosim-LIG/ffi-bitmask
43
+ licenses:
44
+ - BSD-2-Clause
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.9.3
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.5.2
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: bitmask support for ffi
66
+ test_files: []