Skip to content

Commit

Permalink
use parent when possible (#54)
Browse files Browse the repository at this point in the history
If possible, child classes can use the parent's equivalent member and
pointer constructor.
  • Loading branch information
goatshriek authored Jan 9, 2020
1 parent 591a420 commit 9703eb3
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 12 deletions.
7 changes: 6 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Python class generation.
- Perl class generation.

## [0.4.0] - 2020-01-02
## [0.4.0] - 2020-01-08
### Added
- Inequality conditions for rules (less-than, less-than-equal, greater-than,
greater-than-equal).
- Classes who's parent wraps the same equivalent struct will re-use the
equivalent pointer member of the parent class.
- Pointer classes who's parent wraps the same equivalent struct will use the
parent's pointer constructor as the initializer for their own pointer
constructor.

## [0.3.0] - 2020-01-01
### Added
Expand Down
56 changes: 46 additions & 10 deletions lib/wrapture/class_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,12 @@ def overloads?(parent_spec)

# The name of the parent of this class, or nil if there is no parent.
def parent_name
@spec['parent']['name'] if @spec.key?('parent')
@spec['parent']['name'] if child?
end

# Determines if this class is a wrapper for a struct pointer or not.
def pointer_wrapper?
@spec['type'] == 'pointer'
end

# The name of the equivalent struct of this class.
Expand Down Expand Up @@ -208,6 +213,11 @@ def type?(type)

private

# True if the class has a parent.
def child?
@spec.key?('parent')
end

# Gives the content of the class declaration to a block, line by line.
def declaration_contents
yield "#ifndef #{header_guard}"
Expand All @@ -222,7 +232,7 @@ def declaration_contents
yield "namespace #{@spec['namespace']} {"
yield

parent = if @spec.key?('parent')
parent = if child?
": public #{parent_name} "
else
''
Expand All @@ -237,7 +247,7 @@ def declaration_contents
end

yield
yield " #{@struct.declaration equivalent_name};"
equivalent_member_declaration { |line| yield " #{line}" }
yield

member_constructor_declaration { |line| yield " #{line}" }
Expand Down Expand Up @@ -273,7 +283,7 @@ def declaration_includes
includes.concat(const.declaration_includes)
end

includes.concat(@spec['parent']['includes']) if @spec.key?('parent')
includes.concat(@spec['parent']['includes']) if child?

includes.uniq
end
Expand Down Expand Up @@ -341,6 +351,22 @@ def definition_includes
includes.uniq
end

# Yields the declaration of the equivalent member if this class has one.
#
# A class might not have an equivalent member if it is able to use the
# parent class's, for example if the child class wraps the same struct.
def equivalent_member_declaration
if child?
parent_spec = @scope.type(parent_name)
member_reusable = !parent_spec.nil? &&
parent_spec.struct_name == @struct.name &&
parent_spec.pointer_wrapper? == pointer_wrapper?
return if member_reusable
end

yield "#{@struct.declaration(equivalent_name)};"
end

# Gives the name of the equivalent struct.
def equivalent_name
"#{'*' if pointer_wrapper?}equivalent"
Expand Down Expand Up @@ -467,7 +493,8 @@ def pointer_constructor_definition
func.constructor? && func.signature.start_with?(signature_prefix)
end

yield "#{@spec['name']}::#{pointer_constructor_signature} {"
initializer = pointer_constructor_initializer
yield "#{@spec['name']}::#{pointer_constructor_signature} #{initializer}{"

if pointer_wrapper?
yield ' this->equivalent = equivalent;'
Expand All @@ -481,16 +508,25 @@ def pointer_constructor_definition
yield '}'
end

# The initializer for the pointer constructor, if one is available, or an
# empty string if not.
def pointer_constructor_initializer
if pointer_wrapper? && child?
parent_spec = @scope.type(parent_name)
parent_usable = !parent_spec.nil? &&
parent_spec.pointer_wrapper? &&
parent_spec.struct_name == @struct.name
return ": #{parent_name}( equivalent ) " if parent_usable
end

''
end

# The signature of the constructor given an equivalent strucct pointer.
def pointer_constructor_signature
"#{@spec['name']}( #{@struct.pointer_declaration 'equivalent'} )"
end

# Determines if this class is a wrapper for a struct pointer or not.
def pointer_wrapper?
@spec['type'] == 'pointer'
end

# The signature of the constructor given an equivalent struct type.
def struct_constructor_signature
"#{@spec['name']}( #{@struct.declaration 'equivalent'} )"
Expand Down
15 changes: 15 additions & 0 deletions test/fixtures/pointer_class_and_child.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "0.4.0"
classes:
- name: "ParentPointer"
namespace: "wrapture_test"
type: "pointer"
equivalent-struct:
name: "wrapped_struct"
- name: "ChildPointer"
namespace: "wrapture_test"
type: "pointer"
parent:
name: "ParentPointer"
includes: "ParentPointer.hpp"
equivalent-struct:
name: "wrapped_struct"
19 changes: 18 additions & 1 deletion test/test_pointer_class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# frozen_string_literal: true

# Copyright 2019 Joel E. Anderson
# Copyright 2019-2020 Joel E. Anderson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -68,4 +68,21 @@ def test_pointer_class

File.delete(*classes)
end

def test_pointer_class_and_child
test_spec = load_fixture('pointer_class_and_child')

spec = Wrapture::Scope.new(test_spec)

classes = spec.generate_wrappers
validate_wrapper_results(test_spec, classes)

equivalent_signature = 'struct wrapped_struct \*equivalent;'
refute(file_contains_match('ChildPointer.hpp', equivalent_signature))

parent_initializer = 'equivalent \) : ParentPointer\('
assert(file_contains_match('ChildPointer.cpp', parent_initializer))

File.delete(*classes)
end
end

0 comments on commit 9703eb3

Please sign in to comment.