<commit_before>use strict;
use warnings;

package Clownfish::Binding::Core::Class;
use Clownfish::Util qw( a_isa_b verify_args );
use Clownfish::Binding::Core::Method;
use Clownfish::Binding::Core::Function;
use File::Spec::Functions qw( catfile );

our %new_PARAMS = ( client => undef, );

sub new {
    my $either = shift;
    verify_args( \%new_PARAMS, @_ ) or confess $@;
    my $self = bless { %new_PARAMS, @_, }, ref($either) || $either;

    # Validate.
    my $client = $self->{client};
    confess("Not a Clownfish::Class")
        unless a_isa_b( $client, "Clownfish::Class" );

    # Cache some vars.
    $self->{class_name}      = $client->get_class_name;
    $self->{full_struct_sym} = $client->full_struct_sym;
    $self->{struct_sym}      = $client->get_struct_sym;
    $self->{cnick}           = $client->get_cnick;
    $self->{source_class}    = $client->get_source_class;

    return $self;
}

sub get_prefix { shift->{client}->get_prefix }
sub get_Prefix { shift->{client}->get_Prefix }
sub get_PREFIX { shift->{client}->get_PREFIX }

sub file_path {
    my ( $self, $base_dir, $ext ) = @_;
    my @components = split( '::', $self->{source_class} );
    unshift @components, $base_dir
        if defined $base_dir;
    $components[-1] .= $ext;
    return catfile(@components);
}

sub include_h {
    my $self = shift;
    my @components = split( '::', $self->{source_class} );
    $components[-1] .= '.h';
    return join( '/', @components );
}

sub vtable_var    { uc( shift->{struct_sym} ) }
sub callbacks_var { shift->vtable_var . '_CALLBACKS' }
sub name_var      { shift->vtable_var . '_CLASS_NAME' }

sub name_var_definition {
    my $self           = shift;
    my $prefix         = $self->get_prefix;
    my $PREFIX         = $self->get_PREFIX;
    my $full_var_name  = $PREFIX . $self->name_var;
    my $class_name_len = length( $self->{class_name} );
    return <<END_STUFF;
${prefix}ZombieCharBuf $full_var_name = {
    ${PREFIX}ZOMBIECHARBUF,
    {1}, /* ref.count */
    "$self->{class_name}",
    $class_name_len,
    0
};

END_STUFF
}

sub vtable_type { shift->vtable_var . '_VT' }

sub vtable_definition {
    my $self       = shift;
    my $client     = $self->{client};
    my $parent     = $client->get_parent;
    my @methods    = $client->methods;
    my $name_var   = $self->name_var;
    my $vtable_var = $self->vtable_var;
    my $vt         = $vtable_var . "_vt";
    my $vt_type    = $self->vtable_type;
    my $cnick      = $self->{cnick};
    my $prefix     = $self->get_prefix;
    my $PREFIX     = $self->get_PREFIX;

    # Create a pointer to the parent class's vtable.
    my $parent_ref
        = defined $parent
        ? "$PREFIX" . $parent->vtable_var
        : "NULL";    # No parent, e.g. Obj or inert classes.

    # Spec functions which implement the methods, casting to quiet compiler.
    my @implementing_funcs
        = map { "(lucy_method_t)" . $_->full_func_sym } @methods;
    my $method_string = join( ",\n        ", @implementing_funcs );
    my $num_methods = scalar @implementing_funcs;

    return <<END_VTABLE

$PREFIX$vt_type $PREFIX$vt = {
    ${PREFIX}VTABLE, /* vtable vtable */
    {1}, /* ref.count */
    $parent_ref, /* parent */
    (${prefix}CharBuf*)&${PREFIX}$name_var,
    ${PREFIX}VTABLE_F_IMMORTAL, /* flags */
    NULL, /* "void *x" member reserved for future use */
    sizeof($self->{full_struct_sym}), /* obj_alloc_size */
    offsetof(${prefix}VTable, methods) 
        + $num_methods * sizeof(lucy_method_t), /* vt_alloc_size */
    (${prefix}Callback**)&${PREFIX}${vtable_var}_CALLBACKS,  /* callbacks */
    {
        $method_string
    }
};

END_VTABLE
}

sub struct_definition {
    my $self                = shift;<commit_msg>Commit LUCY-90, eliminating VTable refcounting and making them (mostly) stateless.<commit_after>use strict;
use warnings;

package Clownfish::Binding::Core::Class;
use Clownfish::Util qw( a_isa_b verify_args );
use Clownfish::Binding::Core::Method;
use Clownfish::Binding::Core::Function;
use File::Spec::Functions qw( catfile );

our %new_PARAMS = ( client => undef, );

sub new {
    my $either = shift;
    verify_args( \%new_PARAMS, @_ ) or confess $@;
    my $self = bless { %new_PARAMS, @_, }, ref($either) || $either;

    # Validate.
    my $client = $self->{client};
    confess("Not a Clownfish::Class")
        unless a_isa_b( $client, "Clownfish::Class" );

    # Cache some vars.
    $self->{class_name}      = $client->get_class_name;
    $self->{full_struct_sym} = $client->full_struct_sym;
    $self->{struct_sym}      = $client->get_struct_sym;
    $self->{cnick}           = $client->get_cnick;
    $self->{source_class}    = $client->get_source_class;

    return $self;
}

sub get_prefix { shift->{client}->get_prefix }
sub get_Prefix { shift->{client}->get_Prefix }
sub get_PREFIX { shift->{client}->get_PREFIX }

sub file_path {
    my ( $self, $base_dir, $ext ) = @_;
    my @components = split( '::', $self->{source_class} );
    unshift @components, $base_dir
        if defined $base_dir;
    $components[-1] .= $ext;
    return catfile(@components);
}

sub include_h {
    my $self = shift;
    my @components = split( '::', $self->{source_class} );
    $components[-1] .= '.h';
    return join( '/', @components );
}

sub vtable_var    { uc( shift->{struct_sym} ) }
sub callbacks_var { shift->vtable_var . '_CALLBACKS' }
sub name_var      { shift->vtable_var . '_CLASS_NAME' }

sub name_var_definition {
    my $self           = shift;
    my $prefix         = $self->get_prefix;
    my $PREFIX         = $self->get_PREFIX;
    my $full_var_name  = $PREFIX . $self->name_var;
    my $class_name_len = length( $self->{class_name} );
    return <<END_STUFF;
${prefix}ZombieCharBuf $full_var_name = {
    ${PREFIX}ZOMBIECHARBUF,
    {1}, /* ref.count */
    "$self->{class_name}",
    $class_name_len,
    0
};

END_STUFF
}

sub vtable_type { shift->vtable_var . '_VT' }

sub vtable_definition {
    my $self       = shift;
    my $client     = $self->{client};
    my $parent     = $client->get_parent;
    my @methods    = $client->methods;
    my $name_var   = $self->name_var;
    my $vtable_var = $self->vtable_var;
    my $vt         = $vtable_var . "_vt";
    my $vt_type    = $self->vtable_type;
    my $cnick      = $self->{cnick};
    my $prefix     = $self->get_prefix;
    my $PREFIX     = $self->get_PREFIX;

    # Create a pointer to the parent class's vtable.
    my $parent_ref
        = defined $parent
        ? "$PREFIX" . $parent->vtable_var
        : "NULL";    # No parent, e.g. Obj or inert classes.

    # Spec functions which implement the methods, casting to quiet compiler.
    my @implementing_funcs
        = map { "(lucy_method_t)" . $_->full_func_sym } @methods;
    my $method_string = join( ",\n        ", @implementing_funcs );
    my $num_methods = scalar @implementing_funcs;

    return <<END_VTABLE

$PREFIX$vt_type $PREFIX$vt = {
    ${PREFIX}VTABLE, /* vtable vtable */
    {1}, /* ref.count */
    $parent_ref, /* parent */
    (${prefix}CharBuf*)&${PREFIX}$name_var,
    0, /* flags */
    NULL, /* "void *x" member reserved for future use */
    sizeof($self->{full_struct_sym}), /* obj_alloc_size */
    offsetof(${prefix}VTable, methods) 
        + $num_methods * sizeof(lucy_method_t), /* vt_alloc_size */
    (${prefix}Callback**)&${PREFIX}${vtable_var}_CALLBACKS,  /* callbacks */
    {
        $method_string
    }
};

END_VTABLE
}

sub struct_definition {
    my $self                = shift;
{'fraction_non_alphanumeric': 0.1596795727636849, 'fraction_numerical': 0.0017356475300400534, 'mean_word_length': 2.917887029288703, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2745926', 'n_tokens_mistral': 2671, 'n_tokens_neox': 2641, 'n_words': 556}