Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions lib/union.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function Union () {

UnionType.defineProperty = defineProperty
UnionType.toString = toString
UnionType.fields = {}
UnionType.allFields = {}

// comply with ref's "type" interface
UnionType.size = 0
Expand All @@ -73,7 +73,7 @@ function Union () {
UnionType.get = get
UnionType.set = set

// Read the fields list
// Read the allFields list
var arg = arguments[0]
if (typeof arg === 'object') {
Object.keys(arg).forEach(function (name) {
Expand Down Expand Up @@ -102,7 +102,7 @@ function set (buffer, offset, value) {
var isUnion = value instanceof this
if (isUnion) {
// TODO: optimize - use Buffer#copy()
Object.keys(this.fields).forEach(function (name) {
Object.keys(this.allFields).forEach(function (name) {
// hopefully hit the setters
union[name] = value[name]
})
Expand Down Expand Up @@ -151,7 +151,7 @@ function defineProperty (name, type) {
var field = {
type: type
}
this.fields[name] = field
this.allFields[name] = field

// calculate the new size and alignment
recalc(this);
Expand All @@ -168,33 +168,34 @@ function defineProperty (name, type) {
}

function recalc (union) {
// reset size and alignment
union.size = 0
union.alignment = 0
var biggest
var fieldNames = Object.keys(union.allFields)

var fieldNames = Object.keys(union.fields)

// loop through to set the size of the union of the largest member field
// and the alignment to the requirements of the largest member
// find the largest member field by size / alignment
fieldNames.forEach(function (name) {
var field = union.fields[name]
var field = union.allFields[name]
var type = field.type

var size = type.indirection === 1 ? type.size : ref.sizeof.pointer
var alignment = type.alignment || ref.alignof.pointer
if (type.indirection > 1) {
alignment = ref.alignof.pointer
}
union.alignment = Math.max(union.alignment, alignment)
union.size = Math.max(union.size, size)
var fields = {}
fields[name] = { type: type }

var current = { fields: fields, size: size, alignment: alignment }

if (!biggest || size > biggest.size || alignment > biggest.alignment) {
biggest = current
}
})

// any padding
var left = union.size % union.alignment
if (left > 0) {
debug('additional padding to the end of union:', union.alignment - left)
union.size += union.alignment - left
}
union.alignment = biggest.alignment;
union.size = biggest.size;
// Pretend like we only have this one field so that
// ffi-napi doesn't overcount the size
union.fields = biggest.fields;
}


Expand Down
8 changes: 4 additions & 4 deletions test/union.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ describe('Union', function () {
, 'sval': 'string'
})

assert.strictEqual(ref.types.int, U.fields.ival.type)
assert.strictEqual(ref.types.long, U.fields.lval.type)
assert.strictEqual(ref.coerceType('string'), U.fields.sval.type)
assert.strictEqual(ref.types.int, U.allFields.ival.type)
assert.strictEqual(ref.types.long, U.allFields.lval.type)
assert.strictEqual(ref.coerceType('string'), U.allFields.sval.type)
})

})
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('Union', function () {
assert.equal(expectedAlignment, unionType.alignment, 'test' + testNumber +
': __alignof__(): expected ' + unionType.alignment + ' to equal ' + expectedAlignment)
})
Object.keys(unionType.fields).forEach(function (name) {
Object.keys(unionType.allFields).forEach(function (name) {
if ('skip' == name) return;
// these tests just verify the assumption that the
// offset of every field is always 0
Expand Down