class AutoC::Composite

@abstract

Constants

DEFINITIONS
PRIVATE

Attributes

_master[R]
visibility[R]

Public Class Methods

allocator(= @allocator) click to toggle source
# File lib/autoc/composite.rb, line 92
  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.new(
  interface: %{
    #ifndef AUTOC_INLINE
      #if defined(__cplusplus)
        #define AUTOC_INLINE inline
      #elif defined(__clang__)
        #define AUTOC_INLINE static __inline __attribute__((unused))
      #elif __STDC_VERSION__ >= 199901L
        #define AUTOC_INLINE static inline
      #else
        #define AUTOC_INLINE static __inline
      #endif
    #endif
    #ifndef AUTOC_EXTERN
      #ifdef __cplusplus
        #define AUTOC_EXTERN extern "C"
      #else
        #define AUTOC_EXTERN extern
      #endif
    #endif
  }
)

allocator=(allocator) click to toggle source
# File lib/autoc/composite.rb, line 90
def self.allocator=(allocator) @allocator = allocator end
decorator(= @decorator) click to toggle source
# File lib/autoc/composite.rb, line 88
  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.new(
  interface: %{
    #ifndef AUTOC_INLINE
      #if defined(__cplusplus)
        #define AUTOC_INLINE inline
      #elif defined(__clang__)
        #define AUTOC_INLINE static __inline __attribute__((unused))
      #elif __STDC_VERSION__ >= 199901L
        #define AUTOC_INLINE static inline
      #else
        #define AUTOC_INLINE static __inline
      #endif
    #endif
    #ifndef AUTOC_EXTERN
      #ifdef __cplusplus
        #define AUTOC_EXTERN extern "C"
      #else
        #define AUTOC_EXTERN extern
      #endif
    #endif
  }
)
decorator=(decorator) click to toggle source
# File lib/autoc/composite.rb, line 86
def self.decorator=(decorator) @decorator = decorator end
hasher(= @hasher) click to toggle source
# File lib/autoc/composite.rb, line 98
    def self.hasher = @hasher

    self.hasher = Hasher.instance # Default cycle-xor hasher

    module Decorator
      # Pluggable CamelCase identifier decorator
      CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
        id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
        _ = # Check for leading underscore
          if /^(_+)(.*)/ =~ id
            id = Regexp.last_match(2) # Chop leading underscore
            true
          else
            false
          end
        id = id[0] if abbreviate
        # Convert _separated_names to the CamelCase
        id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
        # Carry over the method name's leading underscore only if the prefix is not in turn underscored
        _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
      }
      # Pluggable _snake_case identifier decorator
      SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
        id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
        # Check for leading underscore
        _ =
          if /^(_+)(.*)/ =~ id
            id = Regexp.last_match(2)
            true
          else
            false
          end
        id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
        # Carry over the method name's leading underscore only if the prefix is not in turn underscored
        _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
      }
    end # Decorator

    self.decorator = Decorator::CAMEL_CASE

  private
    
    def method_missing(meth, *args)
      if (method = @methods[meth]).nil?
        # On anything thats not a defined method return a type-decorated identifier
        # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
        raise "unexpected arguments" unless args.empty?
        identifier(meth)
      else
        method
      end
    end

    # Overridable for custom method in derived classes
    def method_class = Method

    # Create a new type-bound function (aka method)
    def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
      name = name.to_sym
      instance = instance.to_sym
      method = method_class.new(
        self,
        result,
        name,
        parameters, # TODO force parameter types coercion
        inline:,
        visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
        constraint: constraint,
        **kws
      )
      raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
      @methods[instance] = method
      references << method # Avoid introducing cyclic dependency due to the method's dependency on self
      method
    end

    def configure
      method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
        header %{
          @brief Destroy existing value

          @param[out] target value to be destroyed

          This function destroys the value previously constructed with any constructor.
          It involves freeing allocated memory and destroying the constituent values with the respective destructors.

          It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

          @since 2.0
        }
      end
      method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
        header %{
          @brief Create a new value

          @param[out] target value to be created

          This function constructs the value with parameterless constructor.

          Previous contents of `*target` is overwritten.

          Once constructed, the value is to be destroyed with @ref #{destroy}.

          @since 2.0
        }
      end
      method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
        header %{
          @brief Create a copy of source value

          @param[out] target value to be created
          @param[in]  source value to be cloned

          This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

          Previous contents of `*target` is overwritten.

          Once constructed, the value is to be destroyed with @ref #{destroy}.
          
          @since 2.0
        }
      end
      method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
        header %{
          @brief Perform equality testing of two values

          @param[in] left  value to test for equality
          @param[in] right value to test for equality

          @return non-zero if values are considered equal and zero otherwise

          This function returns a non-zero value if specified values are considered equal and zero value otherwise.
          Normally the values' contents are considered on equality testing.

          @since 2.0
        }
      end
      method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
        header %{
          @brief Compute relative ordering of two values

          @param[in] left  value to order
          @param[in] right value to order

          @return negative, positive or zero value depending on comparison of the specified values

          This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

          Normally the values' contents are considered on comparison.

          This function is in general independent to but is expected to be consistent with @ref #{equal} function.

          @since 2.0
        }
      end
      method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
        header %{
          @brief Compute hash code

          @param[in] target value to compute hash code for

          @return hash code

          This function computes a hash code which reflects the value's contents in some way,
          that is two values considered equal must yield identical hash codes.
          Two different values may or may not yield identical hash codes, however.

          @since 2.0
        }
      end
    end

  end # Composite


  # Type-bound C side function
  class Composite::Method < Function

    attr_reader :type
  
    def initialize(type, result, name, parameters, **kws)
      @type = type
      super(result.to_value, self.type.identifier(name), parameters, **kws)
      dependencies << self.type << self.result.to_type
      # TODO register parameters' types as dependencies
    end

    def method_missing(meth, *args) 
      if parameters.has_key?(meth) then parameters[meth]
      elsif type.respond_to?(meth) then type.send(meth, *args)
      else meth
      end
    end

  private

    def render_function_header(stream)
      if public?
        stream << %{
          /**
            #{type.ingroup}
            #{@header}
          */
        }
      else
        stream << Composite::PRIVATE
      end
    end

    def render_declaration_specifier(stream)
      stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
    end

    def render_implementation(stream)
      render_function_definition(stream) if live? && !inline?
    end

  end # Method


  Composite::DEFINITIONS = Code.new(
    interface: %{
      #ifndef AUTOC_INLINE
        #if defined(__cplusplus)
          #define AUTOC_INLINE inline
        #elif defined(__clang__)
          #define AUTOC_INLINE static __inline __attribute__((unused))
        #elif __STDC_VERSION__ >= 199901L
          #define AUTOC_INLINE static inline
        #else
          #define AUTOC_INLINE static __inline
        #endif
      #endif
      #ifndef AUTOC_EXTERN
        #ifdef __cplusplus
          #define AUTOC_EXTERN extern "C"
        #else
          #define AUTOC_EXTERN extern
        #endif
      #endif
    }
  )


end
hasher=(hasher) click to toggle source
# File lib/autoc/composite.rb, line 96
def self.hasher=(hasher) @hasher = hasher end
new(signature, visibility: :public, decorator: nil, allocator: nil, hasher: nil, _master: nil) click to toggle source
Calls superclass method
# File lib/autoc/composite.rb, line 31
def initialize(signature, visibility: :public, decorator: nil, allocator: nil, hasher: nil, _master: nil)
  super(signature)
  @methods = {}
  @hasher = hasher
  @decorator = decorator
  @allocator = allocator
  @visibility = visibility
  dependencies << DEFINITIONS << ASSERT_H << self.memory << self.hasher
  @_master = _master
end
new(*args, **kws, &block) click to toggle source
Calls superclass method
# File lib/autoc/composite.rb, line 42
def self.new(*args, **kws, &block)
  obj = super
  obj.send(:configure)
  obj
end

Public Instance Methods

configure() click to toggle source
# File lib/autoc/composite.rb, line 174
def configure
  method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
    header %{
      @brief Destroy existing value

      @param[out] target value to be destroyed

      This function destroys the value previously constructed with any constructor.
      It involves freeing allocated memory and destroying the constituent values with the respective destructors.

      It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

      @since 2.0
    }
  end
  method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
    header %{
      @brief Create a new value

      @param[out] target value to be created

      This function constructs the value with parameterless constructor.

      Previous contents of `*target` is overwritten.

      Once constructed, the value is to be destroyed with @ref #{destroy}.

      @since 2.0
    }
  end
  method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
    header %{
      @brief Create a copy of source value

      @param[out] target value to be created
      @param[in]  source value to be cloned

      This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

      Previous contents of `*target` is overwritten.

      Once constructed, the value is to be destroyed with @ref #{destroy}.
      
      @since 2.0
    }
  end
  method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
    header %{
      @brief Perform equality testing of two values

      @param[in] left  value to test for equality
      @param[in] right value to test for equality

      @return non-zero if values are considered equal and zero otherwise

      This function returns a non-zero value if specified values are considered equal and zero value otherwise.
      Normally the values' contents are considered on equality testing.

      @since 2.0
    }
  end
  method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
    header %{
      @brief Compute relative ordering of two values

      @param[in] left  value to order
      @param[in] right value to order

      @return negative, positive or zero value depending on comparison of the specified values

      This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

      Normally the values' contents are considered on comparison.

      This function is in general independent to but is expected to be consistent with @ref #{equal} function.

      @since 2.0
    }
  end
  method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
    header %{
      @brief Compute hash code

      @param[in] target value to compute hash code for

      @return hash code

      This function computes a hash code which reflects the value's contents in some way,
      that is two values considered equal must yield identical hash codes.
      Two different values may or may not yield identical hash codes, however.

      @since 2.0
    }
  end
end
const_lvalue(= @clv ||= Value.new(self, constant: true, reference: true)) click to toggle source
# File lib/autoc/composite.rb, line 56
  def const_lvalue = @clv ||= Value.new(self, constant: true, reference: true)

  # Prefix used to generate type-qualified identifiers
  # By default it returns the C side type signature but can be overridden
  # to handle the cases where the signature is not itself a valid C identifier (char*, for example)
  def prefix = signature

  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end
const_rvalue(= @crv ||= Value.new(self, constant: true, reference: true)) click to toggle source
# File lib/autoc/composite.rb, line 54
  def const_rvalue = @crv ||= Value.new(self, constant: true, reference: true)

  def const_lvalue = @clv ||= Value.new(self, constant: true, reference: true)

  # Prefix used to generate type-qualified identifiers
  # By default it returns the C side type signature but can be overridden
  # to handle the cases where the signature is not itself a valid C identifier (char*, for example)
  def prefix = signature

  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  
defgroup(= (public? ? :@public : :@internal).to_s + " @defgroup click to toggle source
# File lib/autoc/composite.rb, line 78
  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.new(
hasher(= (@hasher.nil? ? Composite.hasher : @hasher)) click to toggle source
# File lib/autoc/composite.rb, line 84
  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.new(
  interface: %{
    #ifndef AUTOC_INLINE
      #if defined(__cplusplus)
        #define AUTOC_INLINE inline
      #elif defined(__clang__)
        #define AUTOC_INLINE static __inline __attribute__((unused))
      #elif __STDC_VERSION__ >= 199901L
        #define AUTOC_INLINE static inline
      #else
        #define AUTOC_INLINE static __inline
      #endif
    #endif
    #ifndef AUTOC_EXTERN
      #ifdef __cplusplus
        #define AUTOC_EXTERN extern "C"
      #else
        #define AUTOC_EXTERN extern
      #endif
    #endif
  }
identifier(id, **kws) click to toggle source

Decorate identifier with type-specific prefix

# File lib/autoc/composite.rb, line 66
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method

ingroup(= (public? ? :@public : :@internal).to_s + " @ingroup click to toggle source
# File lib/autoc/composite.rb, line 80
  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.new(
  
inspect(= " click to toggle source
# File lib/autoc/composite.rb, line 63
  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end 
internal?(= @visibility == :internal) click to toggle source
# File lib/autoc/composite.rb, line 72
  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS 
lvalue(= @lv ||= Value.new(self, reference: true)) click to toggle source
# File lib/autoc/composite.rb, line 52
  def lvalue = @lv ||= Value.new(self, reference: true)

  def const_rvalue = @crv ||= Value.new(self, constant: true, reference: true)

  def const_lvalue = @clv ||= Value.new(self, constant: true, reference: true)

  # Prefix used to generate type-qualified identifiers
  # By default it returns the C side type signature but can be overridden
  # to handle the cases where the signature is not itself a valid C identifier (char*, for example)
  def prefix = signature

  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
memory(= (@allocator.nil? ? Composite.allocator : @allocator)) click to toggle source
# File lib/autoc/composite.rb, line 82
  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.new(
  interface: 
method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws) click to toggle source

Create a new type-bound function (aka method)

# File lib/autoc/composite.rb, line 155
def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
  name = name.to_sym
  instance = instance.to_sym
  method = method_class.new(
    self,
    result,
    name,
    parameters, # TODO force parameter types coercion
    inline:,
    visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
    constraint: constraint,
    **kws
  )
  raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
  @methods[instance] = method
  references << method # Avoid introducing cyclic dependency due to the method's dependency on self
  method
end
method_class(= Method) click to toggle source

Overridable for custom method in derived classes

# File lib/autoc/composite.rb, line 152
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end
method_missing(meth, *args) click to toggle source
# File lib/autoc/composite.rb, line 140
def method_missing(meth, *args)
  if (method = @methods[meth]).nil?
    # On anything thats not a defined method return a type-decorated identifier
    # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
    raise "unexpected arguments" unless args.empty?
    identifier(meth)
  else
    method
  end
end
prefix(= signature) click to toggle source

Prefix used to generate type-qualified identifiers By default it returns the C side type signature but can be overridden to handle the cases where the signature is not itself a valid C identifier (char*, for example)

# File lib/autoc/composite.rb, line 61
  def prefix = signature

  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

private?(= @visibility == :private) click to toggle source
# File lib/autoc/composite.rb, line 70
  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::
public?(= @visibility == :public) click to toggle source
# File lib/autoc/composite.rb, line 68
  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


respond_to_missing?(meth, include_private = false) click to toggle source
Calls superclass method
# File lib/autoc/composite.rb, line 74
  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = 
rvalue(= @rv ||= Value.new(self, reference: true)) click to toggle source
# File lib/autoc/composite.rb, line 50
  def rvalue = @rv ||= Value.new(self, reference: true)

  def lvalue = @lv ||= Value.new(self, reference: true)

  def const_rvalue = @crv ||= Value.new(self, constant: true, reference: true)

  def const_lvalue = @clv ||= Value.new(self, constant: true, reference: true)

  # Prefix used to generate type-qualified identifiers
  # By default it returns the C side type signature but can be overridden
  # to handle the cases where the signature is not itself a valid C identifier (char*, for example)
  def prefix = signature

  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && 
to_value(= Value.new(self)) click to toggle source
# File lib/autoc/composite.rb, line 48
  def to_value = Value.new(self)

  def rvalue = @rv ||= Value.new(self, reference: true)

  def lvalue = @lv ||= Value.new(self, reference: true)

  def const_rvalue = @crv ||= Value.new(self, constant: true, reference: true)

  def const_lvalue = @clv ||= Value.new(self, constant: true, reference: true)

  # Prefix used to generate type-qualified identifiers
  # By default it returns the C side type signature but can be overridden
  # to handle the cases where the signature is not itself a valid C identifier (char*, for example)
  def prefix = signature

  def inspect = "#{signature} <#{self.class}>"

  # Decorate identifier with type-specific prefix
  def identifier(id, **kws) = (@decorator.nil? ? Composite.decorator : @decorator).(self, id, **kws)

  def public? = @visibility == :public

  def private? = @visibility == :private

  def internal? = @visibility == :internal

  def respond_to_missing?(meth, include_private = false) = @methods.has_key?(meth) ? true : super

  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? 
type_tag(= signature) click to toggle source
# File lib/autoc/composite.rb, line 76
  def type_tag = signature

  def defgroup = (public? ? :@public : :@internal).to_s + " @defgroup #{signature} #{type_tag}"

  def ingroup = (public? ? :@public : :@internal).to_s + " @ingroup #{signature}"

  def memory = (@allocator.nil? ? Composite.allocator : @allocator)

  def hasher = (@hasher.nil? ? Composite.hasher : @hasher)

  def self.decorator=(decorator) @decorator = decorator end

  def self.decorator = @decorator

  def self.allocator=(allocator) @allocator = allocator end

  def self.allocator = @allocator

  self.allocator = Allocator.instance # Standard C malloc() & free() memory handler

  def self.hasher=(hasher) @hasher = hasher end

  def self.hasher = @hasher

  self.hasher = Hasher.instance # Default cycle-xor hasher

  module Decorator
    # Pluggable CamelCase identifier decorator
    CAMEL_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      _ = # Check for leading underscore
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2) # Chop leading underscore
          true
        else
          false
        end
      id = id[0] if abbreviate
      # Convert _separated_names to the CamelCase
      id = type.prefix + id.split('_').collect{ |s| s[0].upcase << s[1..-1] }.join
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
    # Pluggable _snake_case identifier decorator
    SNAKE_CASE = -> (type, symbol, abbreviate: false, **kws) {
      id = symbol.to_s.sub(/[!?]$/, '') # Strip trailing !?
      # Check for leading underscore
      _ =
        if /^(_+)(.*)/ =~ id
          id = Regexp.last_match(2)
          true
        else
          false
        end
      id = abbreviate ? "#{type.prefix}#{id[0]}" : "#{type.prefix}_#{id}"
      # Carry over the method name's leading underscore only if the prefix is not in turn underscored
      _ && !type.prefix.start_with?('_') ? Regexp.last_match(1) + id : id
    }
  end # Decorator

  self.decorator = Decorator::CAMEL_CASE

private
  
  def method_missing(meth, *args)
    if (method = @methods[meth]).nil?
      # On anything thats not a defined method return a type-decorated identifier
      # This allows to generate arbitrary type-qualified identifiers with #{type.foo}
      raise "unexpected arguments" unless args.empty?
      identifier(meth)
    else
      method
    end
  end

  # Overridable for custom method in derived classes
  def method_class = Method

  # Create a new type-bound function (aka method)
  def method(result, name, parameters, inline: false, visibility: nil, constraint: true, instance: name, **kws)
    name = name.to_sym
    instance = instance.to_sym
    method = method_class.new(
      self,
      result,
      name,
      parameters, # TODO force parameter types coercion
      inline:,
      visibility: (visibility.nil? ? self.visibility : visibility), # Method's visibility property can be borrowed from the type itself
      constraint: constraint,
      **kws
    )
    raise "##{instance} method redefinition is not allowed" if @methods.has_key?(instance)
    @methods[instance] = method
    references << method # Avoid introducing cyclic dependency due to the method's dependency on self
    method
  end

  def configure
    method(:void, :destroy, { target: lvalue }, constraint: -> { destructible? }).configure do
      header %{
        @brief Destroy existing value

        @param[out] target value to be destroyed

        This function destroys the value previously constructed with any constructor.
        It involves freeing allocated memory and destroying the constituent values with the respective destructors.

        It is an error to use the value after call to this function (`*target` is considered to contain garbage afterwards).

        @since 2.0
      }
    end
    method(:void, :create, { target: lvalue }, instance: :default_create, constraint: -> { default_constructible? }).configure do
      header %{
        @brief Create a new value

        @param[out] target value to be created

        This function constructs the value with parameterless constructor.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.

        @since 2.0
      }
    end
    method(:void, :copy, { target: lvalue, source: const_rvalue }, constraint: -> { copyable? }).configure do
      header %{
        @brief Create a copy of source value

        @param[out] target value to be created
        @param[in]  source value to be cloned

        This function is meant to an independent copy (a clone) of `*source` value in place of `*target`.

        Previous contents of `*target` is overwritten.

        Once constructed, the value is to be destroyed with @ref #{destroy}.
        
        @since 2.0
      }
    end
    method(:int, :equal, { left: const_rvalue, right: const_rvalue }, constraint: -> { comparable? }).configure do
      header %{
        @brief Perform equality testing of two values

        @param[in] left  value to test for equality
        @param[in] right value to test for equality

        @return non-zero if values are considered equal and zero otherwise

        This function returns a non-zero value if specified values are considered equal and zero value otherwise.
        Normally the values' contents are considered on equality testing.

        @since 2.0
      }
    end
    method(:int, :compare, { left: const_rvalue, right: const_rvalue }, constraint: -> { orderable? }).configure do
      header %{
        @brief Compute relative ordering of two values

        @param[in] left  value to order
        @param[in] right value to order

        @return negative, positive or zero value depending on comparison of the specified values

        This function returns negative value if `left` precedes `right`, positive value if `left` follows `right` and zero if both values are considered equal.

        Normally the values' contents are considered on comparison.

        This function is in general independent to but is expected to be consistent with @ref #{equal} function.

        @since 2.0
      }
    end
    method(:size_t, :hash_code, { target: const_rvalue }, constraint: -> { hashable? } ).configure do
      header %{
        @brief Compute hash code

        @param[in] target value to compute hash code for

        @return hash code

        This function computes a hash code which reflects the value's contents in some way,
        that is two values considered equal must yield identical hash codes.
        Two different values may or may not yield identical hash codes, however.

        @since 2.0
      }
    end
  end

end # Composite


# Type-bound C side function
class Composite::Method < Function

  attr_reader :type

  def initialize(type, result, name, parameters, **kws)
    @type = type
    super(result.to_value, self.type.identifier(name), parameters, **kws)
    dependencies << self.type << self.result.to_type
    # TODO register parameters' types as dependencies
  end

  def method_missing(meth, *args) 
    if parameters.has_key?(meth) then parameters[meth]
    elsif type.respond_to?(meth) then type.send(meth, *args)
    else meth
    end
  end

private

  def render_function_header(stream)
    if public?
      stream << %{
        /**
          #{type.ingroup}
          #{@header}
        */
      }
    else
      stream << Composite::PRIVATE
    end
  end

  def render_declaration_specifier(stream)
    stream << (inline? ? 'AUTOC_INLINE ' : 'AUTOC_EXTERN ')
  end

  def render_implementation(stream)
    render_function_definition(stream) if live? && !inline?
  end

end # Method


Composite::DEFINITIONS = Code.