Vector instance VECINST command

Commands in this namespace document operations accepted by an individual Rbc vector command.

VECINST is used below as a placeholder for the actual vector command:

::rbc::vector create x
x set {1 2 3 4 5}
puts [x length]

Vector indices

Vector indices are Tcl-sized integer values adjusted by the vector’s current offset.

The index end refers to the last value. Tcl index expressions based on end are supported, for example:

x index end
x index end-1

The special index ++end denotes the position immediately after the final value and may be used when setting a value to append one element:

x index ++end 10.0

Colon-separated ranges may be used by operations that accept ranges:

x index 2:5

An omitted range endpoint denotes the beginning or end of the vector:

x index 2:
x index :5
x index :

For real vectors, the associated Tcl array additionally supports the special calculated indices min, max, mean, sum, and prod. These calculated indices are not available for complex vectors.

Complex vector operations

Most vector instance operations support complex vectors. The following table summarizes the current status.

Operation

Complex vectors

*

Supported

+

Supported

-

Supported

/

Supported

append

Supported

binread

Supported

clear

Supported

delete

Supported

dup

Supported

expr

Supported

index

Supported

length

Supported

merge

Supported

normalize

Not supported

offset

Supported

populate

Supported

random

Supported

range

Supported

search

Supported

seq

Supported

set

Supported

sort

Not supported

split

Supported

type

Supported

variable

Supported

Operations that combine vector storage, such as append, merge, set, dup, and split, preserve vector types rather than reinterpreting real storage as complex storage or vice versa.

normalize remains real-only because its definition depends on a minimum and maximum ordering. sort likewise remains real-only because complex numbers have no natural ordering relation.

search supports exact-value searches on complex vectors. A two-bound range search is not defined for complex values and is rejected.

The calculated Tcl array indices min, max, mean, sum, and prod remain real-only. Ordinary numeric indices and ranges work with an explicitly mapped complex vector.

Vector expressions

Vector expressions perform arithmetic, comparison, logical, and mathematical operations on vectors.

Expressions can be evaluated with the top-level vector expr command:

vector expr {expression}

or with the expr operation of a vector instance:

VECINST expr {expression}

The top-level form returns the result. The vector-instance form stores the result in VECINST.

For example:

vector create x y

x set {1 2 3 4}
y set {10 20 30 40}

vector expr {x + y}

# -> 11.0 22.0 33.0 44.0
x expr {x * 2}
x range 0 end
# -> 2.0 4.0 6.0 8.0

Scalars and vectors

A numeric scalar is treated as a single value. When one operand is a scalar and the other is a vector, the scalar operation is applied to every component of the vector.

For example:

vector expr {x * 2}
vector expr {x + 10}
vector expr {100 - x}

When both operands are vectors, the operation is performed component by component. The vectors must have compatible lengths.

For example, given:

x set {1 2 3}
y set {10 20 30}

the expression:

vector expr {x * y}

returns:

10.0 40.0 90.0

Vector names, numeric values, Tcl variable substitutions, command substitutions, quoted or braced values, and parenthesized subexpressions may be used as expression operands.

For example:

set scale 10

vector expr {x * $scale}
vector expr {x + [y index 0]}
vector expr {(x + y) / 2}

Operators

The following operators are supported, listed from highest to lowest precedence.

Operators

Description

- !

Unary minus and logical NOT

^

Exponentiation

* / %

Multiplication, division, and remainder

+ -

Addition and subtraction

<< >>

Circular left and right vector shift

< > <= >=

Relational comparison

== !=

Equality and inequality comparison

&&

Logical AND

\|\|

Logical OR

Binary operators at the same precedence level are evaluated from left to right.

Arithmetic operators operate component by component.

For example:

x set {1 2 3}

vector expr {x + 10}
# -> 11.0 12.0 13.0

vector expr {x * 2}
# -> 2.0 4.0 6.0

Comparison operators return 1.0 when the comparison is true and 0.0 when it is false.

For example:

x set {1 5 10}

vector expr {x > 4}
# -> 0.0 1.0 1.0

Logical operators similarly produce 1.0 or 0.0.

The unary ! operator returns 1.0 for a zero-valued component and 0.0 for a non-zero component.

Circular shifts

The << and >> operators perform circular shifts of vector components. They are not integer bit-shift operators.

The right-hand operand must be a scalar specifying the number of positions to shift.

For example:

x set {1 2 3 4}

vector expr {x << 1}
# -> 2.0 3.0 4.0 1.0

vector expr {x >> 1}
# -> 4.0 1.0 2.0 3.0

Values shifted past one end of the vector reappear at the opposite end.

Complex expression operators

Real and complex vectors may be mixed in an expression. Real operands are promoted to complex values with zero imaginary component when required.

Complex expressions support:

  • unary -

  • unary !

  • +, -, *, and /

  • exponentiation with ^

  • circular shifts << and >>

  • equality and inequality with == and !=

  • logical && and ||.

The remainder operator % and the ordered comparisons <, >, <=, and >= are not supported when either operand is complex.

Complex exponentiation uses the principal complex value for non-integral exponents. A finite integral real exponent is handled directly and therefore does not depend on the logarithm branch.

Equality compares both the real and imaginary components. Logical operations treat a complex value as false only when both components are zero. Equality and logical operations return real 0.0 or 1.0 values.

Circular shifts preserve complete complex values. The shift count must be real; a complex scalar with zero imaginary component is accepted as a real shift count.

Mathematical functions

Vector expressions provide mathematical functions in three general categories:

  • component functions, which operate independently on each vector component

  • scalar functions, which reduce a vector to one value

  • vector functions, which transform a vector into another vector.

Component functions

Component functions apply the selected operation independently to every vector component and return a vector of the same length.

Function

Description

abs

Absolute value

acos

Arc cosine

arg

Phase angle of the component

asin

Arc sine

atan

Arc tangent

ceil

Smallest integral value not less than the component

conj

Complex conjugate

cos

Cosine

cosh

Hyperbolic cosine

exp

Exponential

floor

Largest integral value not greater than the component

imag

Imaginary component

log

Natural logarithm

log10

Base-10 logarithm

random

Generates a pseudo-random value in the range [0.0, 1.0) for each component

real

Real component

round

Rounds to the nearest integral value

sin

Sine

sinh

Hyperbolic sine

sqrt

Square root

tan

Tangent

tanh

Hyperbolic tangent

For example:

x set {1 4 9 16}

vector expr {sqrt(x)}
# -> 1.0 2.0 3.0 4.0

Functions may be combined with operators and other functions:

vector expr {sin(x) * 2}
vector expr {sqrt(abs(x))}

The random function ignores the values of its input components and generates one pseudo-random value for each component:

x length 100

set values [vector expr {random(x)}]

The number of generated values is therefore determined by the length of the argument vector.

Scalar functions

Scalar functions reduce a vector to a single numeric value.

Function

Description

adev

Average absolute deviation from the mean

kurtosis

Fisher excess kurtosis

length

Number of finite components

max

Maximum finite component

mean

Arithmetic mean

median

Median value

min

Minimum finite component

nz

Number of non-zero components

prod

Product of the components

q1

First quartile

q3

Third quartile

sdev

Sample standard deviation

skew

Skewness

sum

Sum of the components

var

Sample variance

For example:

x set {1 2 3 4 5}

vector expr {mean(x)}
# -> 3.0

vector expr {sum(x)}
# -> 15.0

vector expr {min(x)}
# -> 1.0

vector expr {max(x)}
# -> 5.0

Scalar functions can participate in larger expressions:

vector expr {x - mean(x)}
vector expr {x / max(x)}

Vector functions

Vector functions transform their argument and return another vector.

Function

Description

norm

Normalizes the components to the range [0.0, 1.0]

sort

Returns the components sorted in ascending order

For example:

x set {30 10 20}

vector expr {sort(x)}
# -> 10.0 20.0 30.0

Normalization maps the minimum component to 0.0 and the maximum component to 1.0:

x set {10 20 30}

vector expr {norm(x)}
# -> 0.0 0.5 1.0

Mathematical functions on complex vectors

Mathematical functions that have an unambiguous complex definition are supported directly.

The projection functions return real values:

  • abs(z) returns the magnitude |z|.

  • arg(z) returns the phase angle.

  • real(z) returns the real component.

  • imag(z) returns the imaginary component.

conj, sqrt, exp, log, log10, sin, cos, tan, sinh, cosh, tanh, asin, acos, and atan return complex values when their input is complex.

ceil, floor, and round operate independently on the real and imaginary components.

random applied to a complex vector produces a complex vector in which the real and imaginary components are generated independently in the range [0.0, 1.0).

The following reductions support complex vectors:

Function

Result

Complex definition

adev

Real

Mean of abs(z - mean(z))

length

Real

Number of finite complex values

mean

Complex

Arithmetic mean

nz

Real

Number of values other than 0+0i

prod

Complex

Product of the values

sdev

Real

Square root of the Hermitian sample variance

sum

Complex

Sum of the values

var

Real

Hermitian sample variance Σ abs(z - mean(z))^2 / (n - 1)

kurtosis, max, median, min, q1, q3, and skew remain real-only. The vector functions norm and sort are also real-only.

No implicit ordering of complex numbers is introduced for these operations.

Expression results

The result of vector expr is returned to the caller. Complex values are returned as {real imag} pairs:

vector expr {{1 2} + {3 -1}}
# -> {4.0 1.0}

The instance form stores the expression result directly in the vector:

x expr {x * 2}

A complex vector can store either a complex result or a real result; a real result is promoted to complex values with zero imaginary components.

A real vector cannot store a complex expression result:

vector create r
vector create c -type complex

c set {{1 2} {3 4}}
r expr {c + 1}
# error: can't store complex expression result in real vector

C language API

Rbc vectors can be created, inspected, modified, and destroyed directly from C code. This is useful for Tcl extensions that generate or acquire large numeric data sets and want to make those values available to Tcl scripts or graph elements without converting every value to and from a Tcl list.

Include the Rbc public header:

#include <rbc.h>

Rbc exports its public C interface through the Rbc stubs table. An extension using the stubs interface should initialize it before calling Rbc functions:

static int InitRbcApi(Tcl_Interp *interp, const char *version) {
    if (Rbc_InitStubs(interp, version, 0) == NULL) {
        return TCL_ERROR;
    }

    return TCL_OK;
}

version is the minimum Rbc package version required by the extension. Rbc_InitStubs also ensures that the Rbc package is loaded in the interpreter.

Vector representation

Rbc_Vector is an opaque public type:

typedef struct Rbc_Vector_s Rbc_Vector;

Applications must not access the internal vector structure directly. Use the public accessor and mutation functions described below.

Every vector has one of two numeric types:

typedef enum {
    RBC_VECTOR_REAL = 0,
    RBC_VECTOR_COMPLEX
} Rbc_VectorType;

Complex values use the portable public representation:

typedef struct {
    double real;
    double imag;
} Rbc_Complex;

Rbc_Complex deliberately does not use the native C complex type, so the public ABI does not depend on compiler-specific complex-number support.

Public vector functions

The following vector functions are exported through the Rbc stubs interface:

Function

Description

int Rbc_CreateVector(Tcl_Interp *interp, const char *vecName, Tcl_Size size, Rbc_Vector **vecPtrPtr)

Creates a real vector using the traditional Tcl command and automatic array mapping.

int Rbc_GetVector(Tcl_Interp *interp, const char *vecName, Rbc_Vector **vecPtrPtr)

Looks up an existing real or complex vector.

int Rbc_ResizeVector(Rbc_Vector *vecPtr, Tcl_Size nValues)

Changes the logical vector length while preserving its numeric type.

char *Rbc_NameOfVector(Rbc_Vector *vecPtr)

Returns the vector name. The returned string belongs to Rbc.

int Rbc_ResetVector(Rbc_Vector *vecPtr, double *dataArr, Tcl_Size nValues, Tcl_Size arraySize, Tcl_FreeProc *freeProc)

Replaces the storage of a real vector.

double *Rbc_VectorData(Rbc_Vector *vecPtr)

Returns real-vector storage, or NULL for a complex vector.

Tcl_Size Rbc_VectorLength(Rbc_Vector *vecPtr)

Returns the logical number of vector values.

Tcl_Size Rbc_VectorSize(Rbc_Vector *vecPtr)

Returns the current vector capacity in values.

int Rbc_VectorDirty(Rbc_Vector *vecPtr)

Returns the vector update counter.

int Rbc_VectorExists2(Tcl_Interp *interp, const char *vecName)

Tests whether a named vector exists.

void Rbc_FreeVector(Rbc_Vector *vecPtr)

Destroys the vector and releases its resources.

Rbc_VectorType Rbc_VectorGetType(Rbc_Vector *vecPtr)

Returns RBC_VECTOR_REAL or RBC_VECTOR_COMPLEX.

int Rbc_VectorGetRange(Rbc_Vector *vecPtr, double *minPtr, double *maxPtr)

Returns the minimum and maximum of a real vector. Returns TCL_ERROR for a complex vector.

int Rbc_CreateVectorWithType(Tcl_Interp *interp, const char *vecName, Tcl_Size size, Rbc_VectorType type, Rbc_Vector **vecPtrPtr)

Creates a real or complex vector of the requested type.

int Rbc_ResetComplexVector(Rbc_Vector *vecPtr, Rbc_Complex *dataArr, Tcl_Size nValues, Tcl_Size arraySize, Tcl_FreeProc *freeProc)

Replaces the storage of a complex vector.

Rbc_Complex *Rbc_VectorComplexData(Rbc_Vector *vecPtr)

Returns complex-vector storage, or NULL for a real vector.

void Rbc_VectorChanged(Rbc_Vector *vecPtr)

Reports that the existing vector storage was modified in place without changing its storage or ownership contract.

void Rbc_VectorChangedRange(Rbc_Vector *vecPtr, Tcl_Size first, Tcl_Size last)

Reports that the inclusive range first through last of existing vector storage was modified in place. Storage, length, capacity, type, and ownership remain unchanged.

Functions returning int as a Tcl status return TCL_OK on success and TCL_ERROR on failure. When an interpreter is available, an explanatory error message is left in its result.

Vector lengths and capacities use Tcl_Size, allowing the C interface to represent Tcl 9-sized vectors.

Reading vector data

Rbc_GetVector obtains the opaque representation of an existing real or complex vector. Use Rbc_VectorGetType before selecting the storage accessor.

static int InspectVector(Tcl_Interp *interp, const char *name) {
    Rbc_Vector *vecPtr;
    Tcl_Size nValues;

    if (Rbc_GetVector(interp, name, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
    nValues = Rbc_VectorLength(vecPtr);
    switch (Rbc_VectorGetType(vecPtr)) {
    case RBC_VECTOR_REAL: {
        double *dataArr = Rbc_VectorData(vecPtr);
        /* Use dataArr[0] ... dataArr[nValues - 1]. */
        break;
    }
    case RBC_VECTOR_COMPLEX: {
        Rbc_Complex *dataArr = Rbc_VectorComplexData(vecPtr);
        /* Use dataArr[i].real and dataArr[i].imag. */
        break;
    }
    }
    return TCL_OK;
}

Storage returned by either accessor belongs to the vector and must not be freed by the caller. The pointer may become invalid after an operation that resizes, resets, or destroys the vector.

Updating vectors from C

Rbc_VectorData and Rbc_VectorComplexData return mutable storage. A caller may update that storage directly as long as no operation that can resize, replace, or destroy the vector is performed while the pointer is being used.

Direct writes do not themselves invalidate cached vector information or notify vector clients. After modifying existing storage in place, the caller must report the change with either:

Rbc_VectorChanged(vecPtr);

or:

Rbc_VectorChangedRange(vecPtr, first, last);

Rbc_VectorChangedRange should be preferred when the exact modified source interval is known.

first and last are zero-based inclusive source indices and must describe values already present in the vector. The operation reports a content change only; it does not resize the vector or change its storage ownership.

For example, a C extension updating part of a real waveform can write directly into the vector and then report exactly which samples changed:

static int UpdateSamples(Tcl_Interp *interp, const char *name, Tcl_Size first, Tcl_Size last, const double
    *values) {
    Rbc_Vector *vecPtr;
    double *dataArr;
    Tcl_Size nValues;
    Tcl_Size i;

    if (Rbc_GetVector(interp, name, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
    if (Rbc_VectorGetType(vecPtr) != RBC_VECTOR_REAL) {
        Tcl_SetObjResult(interp, Tcl_NewStringObj("vector must be real", -1));
        return TCL_ERROR;
    }
    nValues = Rbc_VectorLength(vecPtr);
    if ((first < 0) || (last < first) || (last >= nValues)) {
        Tcl_SetObjResult(interp, Tcl_NewStringObj("changed range is outside the vector", -1));
        return TCL_ERROR;
    }
    dataArr = Rbc_VectorData(vecPtr);
    for (i = first; i <= last; i++) {
        dataArr[i] = values[i - first];
    }
    Rbc_VectorChangedRange(vecPtr, first, last);
    return TCL_OK;
}

Supplying the changed range allows Rbc clients to preserve caches that are independent of the modified samples. For real vectors, Rbc also attempts to maintain the cached global minimum and maximum from the changed interval. If the modification touches information needed to determine an old global extremum, Rbc automatically falls back to a complete range calculation when required.

Graph line elements can use ranged Y-vector notifications to update only the affected part of a persistent display-decimation cache instead of rebuilding source-domain summaries for the complete vector.

Use Rbc_VectorChanged when the modified source interval is unknown, when changes cover effectively the whole vector, or when a caller does not need to provide more precise change information:

static int FillComplexVector(Tcl_Interp *interp, const char *name) {
    Rbc_Vector *vecPtr;
    Rbc_Complex *dataArr;
    Tcl_Size nValues;
    Tcl_Size i;

    if (Rbc_GetVector(interp, name, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
    if (Rbc_VectorGetType(vecPtr) != RBC_VECTOR_COMPLEX) {
        Tcl_SetObjResult(interp, Tcl_NewStringObj("vector must be complex", -1));
        return TCL_ERROR;
    }
    dataArr = Rbc_VectorComplexData(vecPtr);
    nValues = Rbc_VectorLength(vecPtr);
    for (i = 0; i < nValues; i++) {
        dataArr[i].real = (double)i;
        dataArr[i].imag = -(double)i;
    }
    Rbc_VectorChanged(vecPtr);
    return TCL_OK;
}

Both notification functions preserve the current data pointer, vector length, capacity, numeric type, and storage ownership policy. They flush the associated Tcl-array cache when required and notify registered vector clients.

Multiple modifications may be reported as one inclusive changed range when convenient. The range may therefore conservatively include unchanged samples; correctness does not require every value inside the reported interval to have actually changed.

Do not use Rbc_VectorChanged or Rbc_VectorChangedRange to report a resize or storage replacement. Use Rbc_ResizeVector, Rbc_ResetVector, or Rbc_ResetComplexVector for operations that change vector length, storage, or ownership.

Replacing vector storage

Rbc_ResetVector replaces the storage of a real vector. Rbc_ResetComplexVector performs the corresponding operation for a complex vector.

Calling the real reset function for a complex vector, or the complex reset function for a real vector, returns TCL_ERROR.

Both functions accept nValues, arraySize, and freeProc with the same ownership rules.

freeProc

Storage ownership

TCL_VOLATILE

Rbc copies the supplied data into its own storage. The caller retains ownership of dataArr and may reuse or release it immediately after the call returns.

TCL_STATIC

Rbc uses dataArr directly but never frees it. The caller must keep the array valid for as long as the vector uses it.

TCL_DYNAMIC

Rbc takes ownership of dataArr and releases it with Tcl’s allocator when the storage is replaced or the vector is destroyed. The array must therefore have been allocated with compatible Tcl allocation routines such as Tcl_Alloc.

custom Tcl_FreeProc *

Rbc takes ownership of dataArr and invokes the supplied deallocation procedure when the storage is no longer needed.

The ownership policy supplied to a reset operation becomes the vector’s storage contract. This is true even if the supplied data pointer is identical to the vector’s current data pointer.

Therefore use a reset function when installing or replacing storage. When only the contents of already-installed storage have been modified, use Rbc_VectorChangedRange if the modified interval is known, or Rbc_VectorChanged for an unknown/full-vector modification.

nValues specifies the logical number of values currently stored in the vector. arraySize specifies the capacity of the supplied array and must be greater than or equal to nValues.

Passing NULL for dataArr, or an arraySize of 0, resets the vector to an empty vector.

If arraySize is 0, a non-NULL dataArr is not adopted by the vector and ownership does not transfer to Rbc. The caller remains responsible for that storage.

For example, dynamically allocated storage can be transferred directly to a vector:

static int SetGeneratedData(Tcl_Interp *interp, const char *name) {
    Rbc_Vector *vecPtr;
    double *dataArr;
    Tcl_Size nValues;
    Tcl_Size i;

    nValues = 100;
    if (Rbc_GetVector(interp, name, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
    dataArr = (double *)Tcl_Alloc((size_t)nValues * sizeof(double));
    for (i = 0; i < nValues; i++) {
        dataArr[i] = (double)i * (double)i;
    }
    if (Rbc_ResetVector(vecPtr, dataArr, nValues, nValues, TCL_DYNAMIC) != TCL_OK) {
        Tcl_Free((char *)dataArr);
        return TCL_ERROR;
    }
    /*
     * Rbc now owns dataArr.
     * Do not free or reuse it here.
     */
    return TCL_OK;
}

When TCL_DYNAMIC is used, ownership transfers to Rbc only after a successful Rbc_ResetVector call.

Complex reset example:

static int SetComplexData(Tcl_Interp *interp, const char *name) {
    Rbc_Vector *vecPtr;
    Rbc_Complex values[2];

    if (Rbc_GetVector(interp, name, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }

    values[0].real = 1.0;
    values[0].imag = 2.0;
    values[1].real = 3.0;
    values[1].imag = -4.0;

    return Rbc_ResetComplexVector(
        vecPtr, values, 2, 2, TCL_VOLATILE);
}

Creating vectors from C

Rbc_CreateVector is the compatibility interface for creating a real vector:

Rbc_Vector *realPtr;

if (Rbc_CreateVector(interp, "x", 100, &realPtr) != TCL_OK) {
    return TCL_ERROR;
}

To select the numeric type explicitly, use Rbc_CreateVectorWithType:

Rbc_Vector *complexPtr;

if (Rbc_CreateVectorWithType(
        interp, "z", 100, RBC_VECTOR_COMPLEX, &complexPtr) != TCL_OK) {
    return TCL_ERROR;
}

Rbc_CreateVectorWithType follows the Tcl-level mapping convention: a newly created real vector receives its traditional automatic Tcl array mapping, while a newly created complex vector does not.

For example:

static int CreateTimeVector(Tcl_Interp *interp) {
    Rbc_Vector *vecPtr;
    double *dataArr;
    Tcl_Size nValues;
    Tcl_Size i;

    nValues = 1000;
    if (Rbc_CreateVector(interp, "time", nValues, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
    for (i = 0; i < nValues; i++) {
        dataArr[i] = (double)i * 1.0e-6;
    }
    Rbc_VectorChanged(vecPtr);
    return TCL_OK;
}

Directly modifying storage returned by Rbc_VectorData or Rbc_VectorComplexData does not itself invalidate cached values or notify vector clients. Call Rbc_VectorChangedRange after a known ranged modification, or Rbc_VectorChanged when the changed interval is unknown.

Use Rbc_ResetVector or Rbc_ResetComplexVector when replacing the vector’s storage or changing its ownership contract, not merely to announce that existing storage was modified.

Resizing a vector

Rbc_ResizeVector changes a vector’s logical length and notifies clients of the change.

Rbc_Vector *vecPtr;

if (Rbc_GetVector(interp, "data", &vecPtr) != TCL_OK) {
    return TCL_ERROR;
}
if (Rbc_ResizeVector(vecPtr, 10000) != TCL_OK) {
    return TCL_ERROR;
}

Values already in the vector are preserved when possible. When a vector is enlarged, newly created components are initialized to zero.

Testing for a vector

Rbc_VectorExists2 can be used when C code accepts either an existing vector or needs to create one:

Rbc_Vector *vecPtr;

if (Rbc_VectorExists2(interp, "data")) {
    if (Rbc_GetVector(interp, "data", &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
} else {
    if (Rbc_CreateVector(interp, "data", 0, &vecPtr) != TCL_OK) {
        return TCL_ERROR;
    }
}

Destroying a vector

Rbc_FreeVector destroys a vector obtained from Rbc_GetVector or Rbc_CreateVector:

Rbc_Vector *vecPtr;

if (Rbc_GetVector(interp, "temporary", &vecPtr) != TCL_OK) {
    return TCL_ERROR;
}
Rbc_FreeVector(vecPtr);
/*
 * vecPtr is invalid from this point onward.
 */

Destroying the vector also removes its associated Tcl command and array mapping and releases vector storage according to the ownership policy established by Rbc_ResetVector.

Compatibility with older Rbc vector APIs

Older BLT and Rbc manuals describe additional C functions for vector client identifiers, change callbacks, deletion by name, and custom vector indices. Those routines are not part of the current public Rbc stubs interface and are intentionally not documented here.

Use the functions listed in Public vector functions when writing new extensions.


Copyright (c) George Yashin