A guide to the CONNECT/C++
class library for C++ developers
-
Client-to-engine
connection classes
-
Constructors and generating functions
-
Converting CSPobject to s_object
pointer
-
Subscript
and replacement operators
-
Subscript
and arithmetic operators
-
Evaluation
frames for unnamed objects
-
Overview
-
Overview
-
Overview
-
Overview
-
Overview
-
Overview
This chart shows the inheritance trees for specific
classes in CONNECT/C++.
Taken together, the
classes in the CONNECT/C++ Foundation Class Library make up a "client
application framework" — the framework on which you build a client
application for the S engine that can create data objects, perform operations
on objects, call S functions, evaluate S syntax, and get results.
You use specific classes
in CONNECT/C++ to set up a connection to the S engine, create and operate on
data objects, call S functions, and evaluate S syntax. Notification of changes to objects, output
from functions and evaluations, and database attaches and detaches are managed
by the class which sets up the connection to the S engine.
There are several example
client applications provided in the installation directory, if you chose to
have Samples installed during setup.
-
HELLO demonstrates how to create a simple client
application.
-
SPLLM is similar to HELLO but creates an LM object.
-
SSC demonstrates how to
create a simple S engine client with expression evaluation and result output as
well as notification on object modifications.
-
DMatrix demonstrates how
to create and operate on matrices using CSPmatrix.
-
GaussSDL demonstrates how
to use CONNECT/C++ in .Call applications.
-
Euler demonstrates how to use CONNECT/C++ CSPcall class.
These samples are located
in the samples directory under
S_HOME.
Source code for the
CONNECT/C++ class library is included in the sconnect directory under S_HOME.
The CONNECT/C++ Foundation
Class Library is an object-oriented C++ interface to the S engine that allows a
developer to write a client program and S-PLUS modules using data objects and
structures from the S engine, run S functions, as well as evaluate S syntax and
get results. The foundation classes are
for C++ developers who want to construct client applications that will use the
S engine for data processing and computation.
The class library provides
the following features and benefits in a C++ client application and S-PLUS
modules:
·
Classes which encapsulate
the details of connecting to and working with the S engine allow a significant
reduction in the effort and code requirements to write a client application
using the S engine.
·
Classes provide
methods and properties that allow access to all major S objects. This allows the developer to create and work
with S objects without having to know the details of the structure of the
objects themselves.
·
Automatic reference
counting of S objects means that objects are automatically cleaned up when
scope changes in the program.
·
Powerful Vector,
Array, and Matrix classes allow for fast and powerful data manipulation through
easy to use methods.
·
S functions may be
called from the client given the name of the function and a list of arguments
to pass. This enables the client to
access S functions and get results easily.
·
Override-able event
handler methods provide notification to the client application when S objects
change and when output is available from evaluations or data operations.
·
Persistant objects
with names associated with the S database can be created and initialized in one
call. This cuts down the code overhead
in the client application when creating objects.
The class library provides
a set of classes that can be used to create a client application to create and
manipulate persistant data objects, run S functions, parse and evaluate S
expressions, and receive output and notification when objects are changed or
when databases are attached and detached.
The following sections
provide an overview of specific categories of classes used to accomplish these
operations in a client application.

These classes provide
methods to create and operate on arrays, matrices, and vectors. To use these classes to create a data object
in a client application, simply call the object constructor or call the Create() method.
For a persistant object, specify the name of the object if any and an S
syntax expression you wish to be parsed and evaluated and then assigned the
result to this object in order to initialize it with data. Alternatively, a data object can be
constructed using a form of the constructor that takes an optional S syntax
expression as an argument. This is
useful if named (persistant) objects are not required, but intialization is
required. Once the object is created,
methods can be used to operate on the object.
To receive notification in
the client when a data object changes, create a new class in the client
application derived from the appropriate base class and override the virtual
methods for handling object notification.
When a named object is modified or removed, those virtual methods in the
client are called.
For more information on
using specific data object classes, please see the appropriate section on the
specific class.

The CSPcall class allows S
functions to be evaluated with arguments passed to the function from the
client. Arguments are objects derived
from CSPobject, which may include data objects and other S objects. Results are returned as a CSPobject to the
client. To use this class, simply call
the object constructor with the name of the function to run and any arguments
you wish to pass from the client to the function.
For more information on using
CSPcall, please see the section on this class.
![]()
The CSPengineConnect class
manages a connection between the client and the S engine. This connection permits creation of objects
in the permanent frame, creation of persistent unnamed objects outside of .Call
routines, notification in the client when databases are attached or detached,
output routing to the client, and evaluation of S syntax expressions.
To use CSPengineConnect,
create a new class derived from CSPengineConnect in the client, override the
virtual methods for receiving database attach/detach notification, and output
notification, and add a member variable to the client application class object
to record a reference to a single instance of this derived class.
Use of the
CSPengineConnect class is only necessary when one or more of the following
features is desired in the client program:
-
Integrate S+ engine DLLs
with another application (client)
-
Notification in the client
when databases are attached or detached and when changes are made in persistent
objects.
-
Output redirected to the
client
For more information on
using CSPengineConnect, please see the section on this class.
The CSPevaluator class manages memory resource, errors and the
top-evaluation frame. Although it is
optional, instantiating an object of CSPevalutor class at the top of a try
block can speedup the code, and the corresponding catch block will receive
an exception error when unexpected error occurs in the S engine.
To use CSPevaluator,
create an instance of this class at the top of a try block as shown below:
double minValue = 0;
try
{
//Open top-level-evalutor (frame 1) if it
is close
CSPevaluator sEvaluator;
CSPnumeric myNumeric =
sEvaluator.eval("1:10");
minValue = myNumeric.Min(); //minValue =
1
}
//Close top-level-evaluator when sEvaluator is out of scope
catch(...)
{
//Unexpected error occurred in the engine
}
For more information on using CSPevaluator, please
see the section on this class.
The following sections
describe the basic architectural featues in the class library and some of the
specific programming features available in the library that make it possible to
perform S operations efficiently in client programs and modules written in
C++. Classes and methods discussed in
this section are fully documented in the reference sections for the classes.
CSPobject is the abstract
base class of most all of the classes that represent S classes. It provides common functionality to its
derived classes, and its most important data member is:
s_object*
CSPobject::m_ps_object
A class that represents an
S class inherits m_ps_object because CSPobject is its base class. As a smart pointer, a derived class of
CSPobject provides safer methods to manipulate the data pointed by m_ps_object
as compared to using global C functions.
For example, the constructor, the destructor, and the assignment
operators automatically increment and decrement reference counting whenever
appropriate to provide the same data sharing mechanism as that of the SV4 language.
All CSPobject-derived
classes have a method called IsValid() which allows you to test whether the
member m_ps_object is valid or not.
CSPclass::CSPclass(const char* pszExpression);
//
pszExpression is a string representing valid S code.
where ‘class’ is
a CSPobject-derived object
Often, S generating
functions are more convenient than the S method new. Similarly, constructors of CONNECT/C++ classes can provide the
same convenience. This form of the object
constructor parses and evaluates pszExpression and uses the resultant S object as its value. Normally, pszExpression should contain an S expression that calls to an
appropriate generating function.
However, it works for any S expression that returns a valid S object and
the constructor automatically coerces the returned object to the class that it
represents. It increments the reference
count upon completion, as well. In case
of errors, the constructor throws an exception in the client application.
For example:
CSPevaluator s;
CSPinteger
x("1:4"); // x<-1:4
CSPnumeric
y("fuel.frame[,1]"); //
y<-as(fuel.frame[,1], 'numeric')
CSPnumeric z("new('numeric')"); //
z<- new('numeric')
CSPmatrix
A("matrix(1:4, nrow=2)"); //
A<-matrix(1:4,nrow=2)
CSPmatrix
B("1:4"); //
B<-as(1:4, 'matrix')
//
Do something with x,y,z,A,
and B
Two forms of copy constructors
are available:
CSPclass::CSPclass(const CSPclass& sObject);
CSPclass::CSPclass(s_object* ps_object);
where ‘class’ is
a CSPobject-derived object
The copy constructor of a
CONNECT/C++ class behaves like an S assignment operator when the S object name
is first used. They both share the same
data with the object names used to construct them. However, for the CONNECT/C++ classes sharing is not possible if
the classes are incompatible. It
increments the reference count upon completion.
For example:
CSPevaluator s;
CSPnumeric
x("1:4"); // x<-1:4
CSPnumeric
u(x); // u<-x # u shares data
with x
CSPmatrix
A(x); //
A<-as(x,'matrix') # A shares data with x
CSPcharacter
v(x); // v<-as(x,'character') #
no sharing
s_object*
ps_object = x.GetPtr(); //Get pointer to
s_object*
CSPnumeric
U(ps_object); // U shares data with x
CSPmatrix
a(ps_object); // a shares data
with x
CSPclass& CSPclass::operator=(const CSPclass&
sObject);
where ‘class’ is
a CSPobject-derived object
The assignment operator of
an CONNECT/C++ class behaves like an S assignment operator when the S object
name is already used. However, the
left-hand-side object of the operator = is an existing and valid object. It decrements reference count on the old
object and increments reference count on the new object before swapping the two
object pointers.
For example:
CSPevaluator s;
CSPnumeric
x("1:4"); //
x<-1:4
CSPnumeric
u = x; // u<-new('numeric'); u<-x
# u shares data with x
CSPmatrix
A = x; // A<-new('matrix');
A<-as(x,'matrix') # no sharing
CSPnumeric
y; // y<-new("numeric")
u = y; // u<-y # u switches to share data with y
A
= y; // A<-as(y,'matrix') # A switches to share data with y
CSPclass& CSPclass::operator+(const CSPclass&
sObject);
CSPclass& CSPclass::operator-(const CSPclass&
sObject);
CSPclass& CSPclass::operator*(const CSPclass&
sObject);
CSPclass& CSPclass::operator/(const CSPclass&
sObject);
where ‘class’ is
a CSPobject-derived object
CONNECT/C++ contains some
useful overloading operator such as +, -, * and /. These operators perform element-by-element operations in the same
way as in the S language. However, the
* operator for the matrix class is different.
The operator for CSPmatrix is a real matrix multiplication operator
equivalent to the S %*% operator.
For example:
CSPevaluator s;
CSPnumeric
x("1:4"); //
x<-1:4
CSPnumeric
y ("4:1"); // y<-4:1
y
= y+x*x; // y<-y+x*x
CSPmatrix
A("matrix(1:4,nrow=2)"); // A
<- matrix(1:4,nrow=2)
CSPmatrix
B("matrix(4:1,nrow=2)"); // B
<- matrix(4:1,nrow=2)
CSPmatrix
D = A*A + B*B; // D <- A %*% A + B %*% B
s_object*
CSPobject::operator*();
s_object*
CSPobject::operator&();
Sometimes, an application
needs to access the s_object* directly.
For example, the arguments and the return value of all .Call interfaces
must be s_object*. CSPobject provides a
convenient way to automatically convert to s_object*. Simply use a CSPobject wherever a s_object* is required. It automatically invokes a conversion
operator that returns the s_object* as appropriate.
For example:
s_object* myCall()
{
CSPnumeric x("1:10");
return x;
}
s_object *pReturn = myCall();
The return statement, return
x, first typecasts x to type
s_object*. This invokes the operator
*() of the CSPnumeric class (derived from CSPobject) which ensures that the
destructor of x does not delete the object, even if the reference count drops
to zero.
CSPproxy
CSPvector::operator()(long lIndex);
//
Fortran style indexing starting from index 1
CSPproxy
CSParray::operator()(long l1, long l2=1, …);
//
Fortran style indexing and ordering
CONNECT/C++ contains some
useful overloading subscripting operators ‘()’ for the derived classes
CSPvector and CSParray and their derived classes such as CSPnumeric and
CSPmatrix. The proxy class of the
returned object provides supports for read/write and mixed-mode operations.
Automatic conversions from
CSPproxy to scalar C++ built-in types such as long and double invoke the
template function below:
Template<class
T>
CSPproxy::operator
T() const; // rvalue
For example:
CSPevaluator s;
CSPnumeric
x("c(0.1, 0.2, 0.8, 0.9)"); //
x<- c(0.1, 0.2,
0.8, 0.9)
double
d = x(1); // d <-x[1] # d is 0.1
d
= d + x(2); // d<- d+x[1] # d is 0.3
double
e = (long) x(1); //
e<-as.integer(x[2]) # e is
0
long
n = x(1); // n
<-as.integer(x[1]) # n is 0
n
= n + x(2); // n <-
n+as.integer(x[2]) # n is
still 0
and as another example:
CSPevaluator s;
CSPmatrix
A("matrix(c(0.1, 0.2, 0.8, 0.9), 2)");
// A<- matrix(c(0.1, 0.2, 0.8,
0.9), 2)
double
d = A(1,1); // d <-A[1,1] # d is 0.1
d
= d + A(2,1); // d<-
d+A[2,1] # d is 0.3
long
e = (long) A(2,1); //
e<-as.integer(A[2,1]) # e is 0
long
n = A(1,1); // n <-as.integer(A[1,1])
# n is 0
n
= n + A(2,1); // n <-
n+as.integer(A[2,1]) # n is
still 0
CSPproxy&
CSPproxy::operator=(long);
CSPproxy&
CSPproxy::operator=(double);
CSPproxy&
CSPproxy::operator=(const CSPproxy&);
If a subscript operator of
a CSPobject-derived class returns a lvalue object of CSPproxy, the operation
involves replacing an element of the S object.
Since writing data is not possible for a shared S object, CSPproxy must
determine whether to copy data before replacing its elements. This action occurs in one of its overloaded
assignment operations.
For example:
CSPevaluator s;
CSPnumeric
x("1:4"); // x<- 1:4
x(1)
= 0.0; // x[1]<- 0 # x
is not share, simply set x[1] to 0.0
x(2)
= x(1); // x[2]<- x[1] # x is
not share, simply set x[2] to 0.0
CSPnumeric
y(x); // y<- x # y shares data with
x
y(1)=
10.0; // y[1]<- 10 #copy
and replace: y[1] is 10 and x[1] is 0
+, -, * and /
long
CSPproxy::operator+(long)
double
CSPproxy::operator+(double)
…
Some overloaded operators
are available to support mixed-mode arithmetic operations involving
subscripting objects of classes derived from CSPobject. These operators perform
mixed-mode operations following the same rules as S:
For example:
CSPevaluator s;
CSPnumeric
x("1:4"); // x<- 1:4
CSPnumeric
y(x); // y<- x # y shares data with
x
CSPmatrix
A("matrix(1:4,nrow=2)"); // A
<- matrix(1:4,nrow=2)
double
e = A(1,1)+A(1,2); // e
<- A[1,1] + A[1,2]
A(1,2)
= e*(A(1,1)+A(2,1)); //
A[1,2] <- e*(A[1,1]+A[2,1])
A(2,2)
= x(1)*A(1,1)+y(2)*A(2,1); // A[1,2] <-
x[1]*A[1,1]+y[2]*A[2,1]
CSParray
X("array(1:16, c(2,2,2,2))"); //
X<-array(1:16, c(2,2,2,2))
X(1,1,1,1)
= X(2,1,1,1) + e; //
X[1,1,1,1] <- X[2,1,1,1]+e;
X(2,1,1,1)
= y(1) - X(2,1,1,1); // X[2,1,1,1] <- y[1] - X[2,1,1,1];
X(1,2,1,1)
= A(1,1) * X(2,1,1,1); //
X[1,2,1,1] = A[1,1] *
X[2,1,1,1];
double
CSPmatrix::ConditionNumber(void);
CSPmatrix
SPL_Multiply(const CSPmatrix& A, const CSPmatrix& B);
CSPnumeric
SPL_Multiply(const CSPmatrix& A, const CSPnumeric& x);
…
Some overloaded functions
are available for matrix computations.
These computations are multi-threaded on some platforms (currently
Win/NT on Intel multi-processor machines).
For example:
CSPevaluator s;
CSPmatrix A("matrix(5:8,
nrow=2)");
// A<- matrix(5:8, nrow=2)
CSPmatrix
B(A); //
B<- A
CSPmatrix
D = SPL_Multiply(A, B); // D<-A %*% B
CSPnumeric
x("1:2"); // x<-
rnorm(2)
CSPnumeric
y = SPL_Multiply(A, x); // y<- A %*% x
void
CSPobject::Print(void);
For example:
CSPevaluator s;
CSPcharacter
message("'hello'"); // message <- 'hello'
message.Print(); // print(message)
CSPmatrix
M("matrix(1:4,nrow=2)"); // M<-matrix(1:4, nrow=2)
M.Print(); //
print(M)
All CSPobject-derived
objects are placeholders for an s_object that exists in the engine. So, this C++ object can reference a s_object
or none at all, depending on whether the member s_object pointer points to a
valid s_object. All CSPobject-derived
classes have a method called IsValid() which allows you to test whether it is
pointing to a valid s_object or not.
All named objects are
created in a permanent frame associated with an S database and are, therefore,
persistent between calls and between sessions in the S engine. When you create a new CSPobject in your
client program, a new s_object is created in the S engine. When you delete this CSPobject, the s_object
is also released in the engine.
However, when you execute S syntax to remove the s_object that your
CSPobject points to, such as by using ‘rm(myObject)’, or you call the Remove()
method on the object, the CSPobject is not deleted in your client. The OnRemove() method of the CSPobject in
your client is called and the base class version of this method “disconnects”
your CSPobject from the now released s_object by setting the member s_object
pointer to NULL. After this event,
calling IsValid() on the CSPobject will return FALSE.
Deleting the CSPobject in
your client program does not automatically remove the permanent frame s_object
in the S engine that this CSPobject refers to.
You must call the method Remove() to remove the s_object from the
engine.
You can create named
objects using the Create() method of the various object classes derived from
CSPobject, such as CSPnumeric. Whenever
these objects are modified, the OnModify() method is called in your client
program. Whenever these objects are
removed, the OnRemove() method is called in your client program. Only named objects support this kind of
client program notification.
To create a named object
in your client, first derive a new class from the appropriate CSPobject-derived
class, such as CSPnumeric. Then,
construct an instance of this derived class using the constructor, then call
the Create() method to specify the name you wish to give the object. It is important to derive a new class from
the CSPobject-derived class instead of just using the base class directly in
your client because the OnModify() and OnRemove() methods are virtual and must
be overridden in your derived class in the client in order to be notified when
these events occur.
A CSPobject can be
modified in one of two ways. It can be
modified in the client program by using the operators available for the object
to assign and operate on the elements of the object. When this kind of modification is done, it is necessary to call
the Commit() method on the object to commit it to the S engine before any
changes to the object are reflected in the persistent s_object that is
referenced by the object in the client.
Another way it can be modified is by evaluating S syntax, such as by
using CSPengineConnect::SyncParseEval().
When this kind of modification is done, it is not necessary to call
Commit() on the object, as the s_object is automatically updated by the S
engine. For both kinds of modification,
the OnModify() method of the CSPobject is called in the client program. It is important to call the base class
OnModify() in your override of OnModify().
This allows the base class to update the member s_object pointer to point
to the newly modified s_object in the engine.
The s_object member of a
CSPobject can be removed (invalidated) in one of two ways. It can be removed in the client program by
calling the Remove() method on the CSPobject.
This method removes the s_object from the permanent frame and triggers a
call to the OnRemove() method of the CSPobject in the client program. The base class version of OnRemove(), which
should be called at the end of the overridden version in the client, releases
the member s_object from the CSPobject.
Another way it can be removed is by executing S syntax, such as by
CSPengineConnect::SyncParseEval(). This
also triggers a call to the OnRemove() method of the CSPobject in the client program.
For examples of using
CSPobject-derived classes in a client program and responding to OnModify() and
OnRemove() notifications, see the example C++ client program called SSC installed with the program in the samples subdirectory.
Normally, when you create
an unnamed CSPobject in a client routine that you call via .Call, the s_object
corresponding to this CSPobject is “alive” or is valid until the routine ends
and scope changes out of the routine.
For more information on using CONNECT/C++ in .Call applications, see Using
CONNECT/C++ in .Call.
If you create an unnamed
CSPobject when the S evaluator is not open, the s_object corresponding to this
CSPobject may not be valid. This is
usually not adequate for most client applications. Therefore, you need to do the following to ensure that unnamed
CSPobjects created in a client application do not go away until the end of the
client routine:
-
Create an instance of a
CSPevaluator at the top of the scope “{“.
-
Create and use any unnamed
CSPobject-derived objects in the client.
For example:
{
CSPevaluator
s;
CSPnumeric
x(“1:10”);
…
}
For named objects, you do
not have to use the above approach:
simply create named CSPobject-derived objects using the constructor and
a call to CSPobject::Create(). For
further information, see CSPengineConnect::OpenTopLevelEval(),
CSPengineConnect::CloseTopLevelEval(),
and the Create() method for the object type to be created.
CONNECT/C++ can be used as
an effective tool for building reasonably efficient .Call interfaces. The class library reflects the hierarchy of
the SV4 class system. Almost every
CONNECT/C++ class mimics an S class defined in the S language. Such a class encapsulates S data the same
way as the internal C structure that represents the S object of an S
class. Many of its public member
functions perform the same operations as their corresponding S methods. Because each class is a wrapper of the
structure pointer s_object* used by all .Call interfaces, using CONNECT/C++
inside a .Call interface is easy.
NOTE: Only several CONNECT/C++ classes and limited
numbers of member functions are available in the current S-PLUS 6.0 release.
The S function below
implements Gauss-Seidel iterative method for solving a linear system. The input matrix should be diagonally
dominant for its solution to converge. The stronger diagonally dominant is the
faster convergent rate. This sample is
also on disk in the S_HOME/samples/GaussSDL
directory.
gaussSeidel<-
#
gaussSeidel solves a linear system using Gauss-Seidel iterative method.
#
REQUIRED ARGUMENTS:
# A and b are numeric matrix and vector
respectively.
#
VALUE:
# a vector x, solution of A x = b
#
#
Usage:
# A<-matrix(rnorm(100),nrow=10)
# diag(A)<-seq(ncol(A),ncol(A)) #Make it diagonally dominant
# b<-rnorm(ncol(A))
# sys.time({x1<-gaussSeidel(A,b)})
function(A,b)
{
# Hard-coded relative tolerance and max iterations
tol<-1.0e-4
maxItr<-1e4
# Validating
A <- as.matrix(A)
b <- as.numeric(b)
if(ncol(A) != length(b))
stop("ncol(A) !=
length(b)")
# Begin Gauss-Seidel step
x<-b
for(k in 1:maxItr)
{
xOld<-x
for(i in 1:nrow(A))
{
s<-
A[i,i]*x[i]
for(j in 1:ncol(A))
s <- s - A[i,j]*x[j]
x[i] <- (b[i]+s)/A[i,i]
}
# Check convergence; continue if necessary
if(max(abs((x-xOld)/x)) < tol)
return(x);
}
warning("Solution does not converge\n")
return(x)
}
A C++ function using CONNECT/C++ that performs the same task as the
above listed S code is implemented as follows:
#include "sconnect.h"
#include
"gausssdl.h"
s_object*
gaussSeidel(s_object* ps_A, s_object* ps_b)
/**********************************************************************
gaussSeidel solves a linear system using Gauss-Seidel iterative method.
REQUIRED ARGUMENTS:
ps_A and ps_b are numeric matrix and vector respectively.
VALUE:
a vector x, solution of A x = b
S FUNCTION EQUIVALENT:
gaussSeidel() defined in gausssdl.ssc
Usage:
A<-matrix(rnorm(100),nrow=10)
diag(A)<-seq(ncol(A),ncol(A)) # Make it diagonally dominant
b<-rnorm(ncol(A))
source('gausssdl.ssc') # S version of gaussSeidel
sys.time({x1<-gaussSeidel(A,b)}) # timing the S version
sys.time({x2<-.Call('gaussSeidel',A,b)}) #
timing the .Call version
all.equal(x1,x2) # Should return T
*********************************************************************/
{
S_EVALUATOR
try
{
//Hard-coded relative tolerance and max iterations
double tol =1e-4;
long maxItr = 1000;
//Constructing and validating C++ objects
CSPmatrix A(ps_A);
CSPnumeric b(ps_b);
if(A.ncol() != b.length())
PROBLEM "A.ncol() != b.length()" ERROR;
//Begin Gauss-Seidel step
CSPnumeric x=b;
for(long k =1; k<= maxItr; k++)
{
CSPnumeric xOld = x;
for(long i= 1; i <= A.nrow(); i++)
{
double s = A(i,i) * x(i);
for(long j = 1; j <= A.ncol(); j++)
s = s - A(i,j) * x(j);
x(i) = (b(i)+s)/A(i,i);
}
//Check convergence; continue if necessary
if(Max(abs((x-xOld)/x)) < tol)
return(x);
}
PROBLEM "Solution does not converge" WARN;
return(x);
}
catch(...)
{
}
return(blt_in_NULL); //return the build-in
NULL object
}

The CSPengineConnect class
manages a connection between the client and the S engine. This connection permits creation of
persistant objects associated with databases, persistant objects not associated
with databases, temporary objects, notification in the client when databases
are attached or detached, output routing to the client, parsing, and evaluating
S syntax expressions.
To use CSPengineConnect,
create a new class derived from CSPengineConnect in the client, override the
virtual methods for receiving database attach/detach notification, and output
notification, and add a member variable to the client application class object
to record a reference to a single instance of this derived class. This class instance will receive
notifications and output routing.
Only the most recently
created instance of the CSPengineConnect-derived class will receive
notification in the client. Multiple
instances of CSPengineConnect classes are not supported in client programs.
Use of a
CSPengineConnect-derived class is only necessary when one of the following
features is desired in the client program:
-
Create objects on the
permanent frame
-
Create unnamed objects that
persist between calls or routines outside of a .Call (see below)
-
Notification in the client
when databases are attached or detached
-
Output redirected to the
client
Normally, when you create
an unnamed CSPobject in a client routine that you call via .Call, the s_object
corresponding to this CSPobject is “alive” or is valid until the routine ends
and scope changes out of the routine.
For more information on using CONNECT/C++ in .Call applications, see Using
CONNECT/C++ in .Call.
If you create a unnamed
CSPobject in a routine outside of a .Call in a client application, the s_object
corresponding to this CSPobject is only valid until the constructor returns to
the caller. This is usually not
adequate for most client applications.
Therefore, to ensure that unnamed CSPobjects created in a client
application do not go away until the end of the client routine, do the
following:
-
Create an instance of a
CSPevaluator at the top of scope “{“.
-
Create any unnamed CSPobject-derived
objects in the client.
Class Members | Hierarchy chart
Required includes:
#include "spengcon.h"
Samples:
S_HOME/samples/ssc
See Also:
Client-To-Engine
connection classes
|
|
|
|
|
Constructs a CSPengineConnect object in various ways. |
|
Creates connection between client and S engine, allowing
specification of command line arguments and a dll search list. |
|
S syntax evaluation |
|
|
Parses and evaluates an expression in S syntax. |
|
|
|
|
|
Creates an S object in a permanent frame and returns a
pointer to a s_object pointer. |
|
|
Assigns an S object and a name for the object to a permanent
frame. |
|
|
Gets the first occurance of a named S object in the
permanant frames. Returns a pointer
to the s_object found. |
|
|
|
|
|
Reads text output sent to stdout by the engine. |
|
|
Reads text output sent to stderr by the engine. |
|
|
|
|
|
Called when a database is attached. |
|
|
Called when a database is detached. |
|
|
Called when there is output to be displayed in the
client as a result of operations or errors from the S engine. |
|
CSPengineConnect
Overview | Hierarchy
chart
CSPengineConnect()
CSPengineConnect(int argc,
char* argv[], char *dlllist[])
|
Parameters |
|
|
argc |
Number of arguments present in argument list argv[], not
including final null. |
|
argv |
Array of char * to be passed to the S engine as a
startup argument list. Contents of
this argument list can consist of the same options that can be passed as the
command-line to SQPE.EXE. |
|
dlllist |
OPTIONAL Array of char * which specifies the list of
DLLs to search for symbols as needed by the S engine to resolve calls. Elements of this list can include dll file
names without path or fully qualified dll pathnames. No wildcards are allowed. |
Use the constructor with the argc, argv[], and dlllist[]
parameters if you need to create a CSPengineConnect-derived object and
initialize the connection at the same time.
Normally, a member of the client application class is used and the
Create() method is called later during initialization of the client
application.
To create an engine connection in the client, derive a class from CSPengineConnect and create a member variable in the client application class to store an instance to this class. Call the Create() method on this member during the client application initialization routine. Pass the list of arguments and dlls to Create(). If the client application is based on MFC, do this during the CWinApp::InitInstance() routine in the client.
// NOTE: Make sure S_HOME
environment variable is set
// before running this example.
int
argc = 2;
char
*argv[2];
//
argv[0] is always expected to be the client program name
argv[0]
= "DocumentSamples.exe";
// Get
the value of S_HOME from the environment
// argv[1] is set to be the current
S_HOME environment setting
if
( !pszSHOMEenv || !*pszSHOMEenv )
pszSHOMEenv = getenv( "S_HOME" );
if ( pszSHOMEenv )
{
static char szArg[_MAX_PATH];
sprintf( szArg, "S_HOME=%s", pszSHOMEenv );
argv[1] = szArg;
}
//
Initialize the
connection
BOOL
bSuccess = m_myEngineConnect.Create(argc, argv);
CSPengineConnect
Overview | Class
Members | Hierarchy chart
virtual int Create(int
argc, char* argv[], char *dlllist[])
1 if successful, 0 if not.
|
Parameters |
|
|
argc |
Number of arguments present in argument list argv[], not
including final null. |
|
argv |
Array of char * to be passed to the S engine as a
startup argument list. Contents of
this argument list can consist of the same options that can be passed as the
command-line to SQPE.EXE. |
|
dlllist |
OPTIONAL Array of char * which specifies the list of
DLLs to search for symbols as needed by the S engine to resolve calls. Elements of this list can include dll file
names without path or fully qualified dll pathnames. No wildcards are allowed. |
Use this method to initialize the client-engine
connection. Normally, a member of the
client application class, derived from CSPengineConnect is used and the
Create() method is called during initialization of the client application.
To create an engine connection in the client, derive a class from CSPengineConnect and create a member variable in the client application class to store an instance to this class. Call the Create() method on this member during the client application initialization routine. Pass the list of arguments and dlls to Create(). If the client application is based on MFC, do this during the CWinApp::InitInstance() routine in the client.
// NOTE: Make sure S_HOME
environment variable is set
// before running this example.
int
argc = 2;
char
*argv[2];
//
argv[0] is always expected to be the client program name
argv[0]
= "DocumentSamples.exe";
argv[1] = "S_HOME=d:\\spluswin";
//
Initialize the connection
BOOL
bSuccess = m_myEngineConnect.Create(argc, argv);
CSPengineConnect
Overview | Class
Members
| Hierarchy
chart
int SyncParseEval(const
char *pszExpression)
1 if successful, 0 if not.
|
Parameters |
|
|
pszExpression |
Any valid S syntax.
If reserved characters are used in this expression string, they must
be escaped properly, following C conventions. |
Use this method to parse and evaluate any valid S syntax and synchronize persistant objects with databases. This method calls the Print method on the returned object from the evaluation to generate output which gets routed to the client application if the appropriate notification handler methods are overridden in the client CSPengineConnect-derived class.
This method may generate an exception in the client program if the S syntax in pszExpression results in an execution error.
BOOL bSuccess = FALSE;
try
{
char pszExpression[] =
"assign( 'myVar',c('item1','item2'),immediate=T,where=1
)";
bSuccess =
m_myEngineConnect.SyncParseEval( pszExpression );
if ( !bSuccess )
{
// Print error in the client program
}
}
catch(...)
{
}
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect()
virtual s_object*
CreateObject(
const
char* pszClass, // class name
const char* pszName, //
object name
const char* pszExpression = NULL,
long
lDataBase = 1 ) // database
Returns a pointer to the permanent frame object created if successful. Returns NULL on failures.
|
Parameters |
|
|
pszClass |
Any valid S class name, such as ‘numeric’, ‘character’,
etc. |
|
pszName |
Name of the object to create. |
|
pszExpression |
Optional S syntax to evaluate and assign the result of
to the newly created object. |
|
lDataBase |
Database position to assign the newly created object to. |
Use this method to create a named object on a permanent frame.
Once created, the object will receive notification in the client, provided the CSPobject-derived class notification handlers are implemented in the client.
The following example creates a new ‘numeric’ object named ‘MyNumeric’ on the permanent frame in database position 1 and initializes it to the sequence from 1 to 10, where CSPmyNumeric is a client class derived from CSPnumeric:
CSPmyNumeric myNumeric;
try
{
myNumeric =
m_myEngineConnect.CreateObject(
"numeric",
"MyNumeric",
"1:10" );
}
catch(...)
{
// Display exception error
}
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::Assign(), CSPengineConnect::get()
virtual void Assign(
const
char* pszName, // object name
const
CSPobject& spObject, // object to assign
long
lDataBase = 1 );
Generates an exception in the client upon failure.
|
Parameters |
|
|
pszName |
Name of the object to assign. |
|
spObject |
A reference to a CSPobject that is to be assigned to a
permanent frame. |
|
lDataBase |
Database position to assign the object to. |
Assigns the CSPobject specified to a permanent frame in a database position using the object name specified. You would normally use this method after you created an unnamed object using a CSPobject constructor in order to assign the object to a permanent frame and to give the object a name.
Once assigned, the object will receive notification in the client, provided the CSPobject-derived class notification handlers are implemented in the client.
The following example creates a new unnamed ‘numeric’ object and initializes it to the sequence from 1 to 10. Then a call to Assign() is made to name this object and assign it to a permanent frame in database position 1. Note: CSPmyNumeric is a client class derived from CSPnumeric so notification will occur in the client when the object is modified:
CSPmyNumeric myNumeric(
"1:10" );
try
{
m_myEngineConnect.Assign(
"MyNumeric",
myNumeric );
}
catch(...)
{
// Display exception error
}
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::CreateObject(),
CSPengineConnect::get()
virtual s_object * get(
const
char* pszName ); // object name
Returns the first occurrence of an object with the name specified, or NULL if not found or on errors.
|
Parameters |
|
|
pszName |
Name of the object to find in the permanent frames. |
Gets an object whose name is specified. This method has the same semantics as the S function “get”. This method will return only the first occurrence of an object with the name specified, if multiple objects exist. The search order is the same as the S database search list.
Once assigned to a new CSPobject-derived object, the object will receive notification in the client, provided the CSPobject-derived class notification handlers are implemented in the client.
The following example creates a new CSPmyNumeric object. Then a call to Find() is made to find a numeric object by the name of ‘MyNumeric’. If found, it is copied to the CSPmyNumeric object so notification will occur in the client. Note: CSPmyNumeric is a client class derived from CSPnumeric so notification will occur in the client when the object is modified:
CSPmyNumeric myNumericFound;
CSPmyNumeric myNumeric;
try
{
myNumeric =
m_myEngineConnect.CreateObject(
"numeric",
"MyNumeric",
"1:10" );
myNumericFound = m_myEngineConnect.get( "MyNumeric" );
}
catch(...)
{
// Display exception error
}
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::CreateObject(),
CSPengineConnect::Assign()
virtual BOOL ReadStdout(
char* pszBuffer, // output data buffer
long
nBufferSize // size of
data buffer
)
Returns TRUE if there are more text to be read else FALSE.
|
Parameters |
|
|
pszBuffer |
Buffers to receive the text character output. |
|
nBufferSize |
Maximum length of (char*) in the first argument. |
Read text output printed to stdout by the S engine. This method allows the client to get a stream of output from the S engine and display it in response to notification that output is available.
The following example shows how to read text output sent by the S engine to the stdout.
const long kMaxLen = 4888;
char
szBuffer[kMaxLen];
try
{
//Print some text
m_myEngineConnect.SyncParseEval("print('Hello\n')");
// Read text sent from the engine to the
standard out
m_myEngineConnect.ReadStdout(szBuffer,
kMaxLen);
}
catch(...)
{
}
CSPengineConnect Overview | Class Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::ReadStderr(), CSPengineConnect::OnOutput()
virtual BOOL ReadStderr(
char* pszBuffer, // output data buffer
long
nBufferSize // size of
data buffer
)
Returns TRUE if there are more text to be read else FALSE.
|
Parameters |
|
|
pszBuffer |
Buffers to receive the text character output. |
|
nBufferSize |
Maximum length of (char*) in the first argument. |
Read text output printed to stderr by the S engine. This method allows the client to get a stream of output from the S engine and display it in response to notification that output is available.
The following example shows how to read text output sent by the S engine to the stderr.
const long kMaxLen = 4888;
char szBuffer[kMaxLen];
try
{
//Generate an error
m_myEngineConnect.SyncParseEval("stop('This is an error')");
}
catch(...)
{
}
// Read text sent from the engine to the standard error
m_myEngineConnect.ReadStderr(szBuffer, kMaxLen);
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::ReadStdout(), CSPengineConnect::OnOutput()
virtual int OnAttach(
s_object* ps_attached );
|
Parameters |
|
|
ps_attached |
An s_object pointer of class “attached” which represents
the attached database. |
Return a 1 in your override of this method to indicate that the notification was successfully processed. Otherwise return 0 on failure.
To use this notification handler, derive a class from CSPengineConnect in the client program, and override the OnAttach() method in this class.
This method is called whenever a database is attached. The attached database information is passed to the client in the ps_attached parameter as a pointer to an s_object of class “attached”.
The following example shows the OnAttach() notification handler overridden in a CSPengineConnect-derived class called CMyEngineConnect in a client application. This handler will be called whenever a database is attached:
int
CSPmyEngineConnect::OnAttach(s_object* ps_attached)
{
// Perform any client operations here, such as printing
// out a notification in the client
program
PRINT_ON_ATTACH(
ps_attached );
return 1;
}
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::OnDetach(), CSPengineConnect::OnOutput()
virtual int OnDetach(
s_object* ps_attached );
|
Parameters |
|
|
ps_attached |
An s_object pointer of class “attached” which represents
the detached database. |
Return a 1 in your override of this method to indicate that the notification was successfully processed. Otherwise return 0 on failure.
To use this notification handler, derive a class from CSPengineConnect in the client program, and override the OnDetach() method in this class.
This method is called whenever a database is detached. The detached database information is passed to the client in the ps_attached parameter as a pointer to an s_object of class “attached”.
The following example shows the OnDetach() notification handler overridden in a CSPengineConnect-derived class called CMyEngineConnect in a client application. This handler will be called whenever a database is attached:
int CSPmyEngineConnect::OnDetach(s_object* ps_attached)
{
// Perform any client operations here, such as printing
// out a notification in the client program
PRINT_ON_DETACH( ps_attached );
return 1;
}
CSPengineConnect
Overview | Class
Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::OnAttach(), CSPengineConnect::OnOutput()
virtual int OnOutput( void
);
Return a 1 in your override of this method to indicate that the notification was successfully processed. Otherwise return 0 on failure.
To use this notification handler, derive a class from CSPengineConnect in the client program, and override the OnOutput() method in this class.
This method is called whenever output (errors or normal output) is available from operations in the S engine. In this handler, the client can get a handle to the S engine standard output and error channels and then read text on these channels and display it appropriately.
The following example shows the OnOutput() notification handler overridden in a CSPengineConnect-derived class called CMyEngineConnect in a client application. This handler will be called whenever output is available:
#include
"stdafx.h"
#include "spl.h"
#include "myengcon.h"
#include "mainfrm.h"
#include "txstring.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMyEngineConnect::CMyEngineConnect()
:
CSPengineConnect()
{
}
CMyEngineConnect::CMyEngineConnect(int
argc, char *argv[], char *dlllist[])
:
CSPengineConnect(argc, argv, dlllist)
{
}
CMyEngineConnect::~CMyEngineConnect()
{
}
int CMyEngineConnect::OnAttach( s_object*
ps_attached)
{
//
Get db name and position
CSPattached
spAttached(ps_attached);
CSPcharacter
spDBName = spAttached.GetDatabaseName();
long
lPosition = spAttached.GetPosition();
//
Format message to display
CTxString
sMsg;
sMsg.Format(
"Attaching %s at position %d\r\n", (const char *)spDBName[0],
lPosition );
TRACE(
sMsg );
//
Display message in output pane of application
AppendToOutputPane(
sMsg );
return
1;
}
int CMyEngineConnect::OnDetach( s_object*
ps_attached)
{
//
Get db name and position
CSPattached
spAttached(ps_attached);
CSPcharacter
spDBName = spAttached.GetDatabaseName();
long
lPosition = spAttached.GetPosition();
//
Format message to display
CTxString
sMsg;
sMsg.Format(
"Detaching %s at position %d\r\n", (const char *)spDBName[0],
lPosition );
TRACE(
sMsg );
//
Display message in output pane of application
AppendToOutputPane(
sMsg );
return
1;
}
int CMyEngineConnect::OnOutput( void )
{
const
long kMaxLen = 4888;
char
szTextOutputBuffer[kMaxLen];
CTxString
strText;
try
{
//
Read text sent from the engine to the standard out
while(ReadStdout(szTextOutputBuffer,
kMaxLen))
{
strText.Unix2Dos(szTextOutputBuffer);
TRACE(
"In CMyEngineConnect::OnOutput() with output: '%s'\n", (const char
*)strText );
AppendToOutputPane(strText);
// Display message in output pane of window
}
//
Read text sent from the engine to the standard err
while(ReadStdout(szTextOutputBuffer,
kMaxLen))
{
strText.Unix2Dos(szTextOutputBuffer);
TRACE(
"In CMyEngineConnect::OnOutput() with error: '%s'\n", (const char
*)strText );
AppendToOutputPane(strText);
// Display message in output pane window
}
}
catch(...)
{
strText.Format("PROBLEM
reading standard out/err");
TRACE(
"In CMyEngineConnect::OnOutput() with error: '%s'\n", (const char
*)strText );
}
return
1;
}
CSPengineConnect Overview
|
Class Members | Hierarchy chart
CSPengineConnect::CSPengineConnect(),
CSPengineConnect::OnAttach(), CSPengineConnect::OnDetach(), CSPengineConnect::ReadStdout(), CSPengineConnect::ReadStderr()
The CSPevaluator class
manages memory resources, errors and the top-evaluation frame. Although it is optional, instantiating an
object of CSPevalutor class at the top of a try block can speedup the
code, and the corresponding catch block will receive an
exception error when unexpected error occurs in the S engine.
To use CSPevaluator,
create an instance of this class at the top of a try block. Then create objects as necessary.
Class Members | Hierarchy chart
Required includes:
#include "speval.h"
Samples:
See Also:
Client-To-Engine
connection classes
|
Construction |
|
|
Constructs a CSPevaluator object in various ways. |
|
S syntax evaluation
|
|
|
Parses and evaluates an expression in S syntax. |
|
|
Top-level-evaluator |
|
|
Opens the top-level-evaluator if it is not open yet. |
|
|
Closes the top-level-evaluator. |
|
|
Returns TRUE if the top-level-evaluator is open. |
|
Other methods
|
|
|
Comparing contents of two S objects. |
|
CSPevalutor
Overview | Hierarchy
chart
CSPevalutor()
Use the default constructor in a try-block to ensure that
the top-level-evaluation frame is open.
If the top-level-evaluation frame were not open yet, the default
constructor would open it. Then, if
there is a server error in the engine an exception is thrown. Your catch block should receive a exception
object. If there is no server error,
the object of class CSPevaluator will close the top-level-evaluation frame when
it desctructor is called.
All S objects, created during the lifetime of a
CSPevaluator object, are local objects by default. These local objects are destroyed automatically when the
CSPevaluator object is going out scope.
However, any global C++ object of class CSPobject attached to a local S
object will automatically be re-attached to a global S object cloned from the
local one. This is automatically done
when the local CSPevaluator object is going out of scope.
The following example demonstrates the use of CSPevaluator::CSPevaluator()
CSPnumeric snPerm ;
try
{
CSPevaluator s; //open
top-level-evaluator by default
CSPnumeric snLocal("c(1,2,3)");
snPerm = snLocal;
}
catch(...)
{
}
CSPevaluator
Overview | Class Members | Hierarchy chart
CSPevaluator::Open(),
CSPevaluator::Close(), CSPevaluator::IsOpen()
s_object* eval(const char
*pszExpression)
S object result of evaluating the S expression.
|
Parameters |
|
|
pszExpression |
Any valid S syntax.
If reserved characters are used in this expression string, they must
be escaped properly, following C conventions. |
Use this method to parse and evaluate any valid S syntax.
This method may generate an exception in the client program if the S syntax in pszExpression results in an execution error.
The following example demonstrates the use of CSPevaluator::eval()
CSPcharacter scharPerm ;
try
{
CSPevaluator s; //open
top-level-evaluator by default
CSPcharacter sobjLocal
=
s.eval("'hello3'");
scharPerm
= sobjLocal;
}
catch(...)
{
}
CSPevaluator Overview | Class
Members | Hierarchy
chart
CSPengineConnect::SyncParseEval(),
CSPcall::Eval()
BOOL
Open()
Returns TRUE if it opens the top-level-evaluator successfully else FALSE.
This method opens the top-level-evaluation frame if it is
not already open. If the
top-level-evaluator were already open, you can use this method to ensure a
return of program control to a local block during a severed error occurred in
the S engine. The S engine (C code)
performs a long jump when there is a severed error, CSPevaluator::Open() turns
the long jump to an exception error in C++.
The following example demonstrates the use of CSPevaluator::Open()
int nTest = 0;
CSPevaluator
sEvaluator; //Open top-level-evalutor
try
{
sEvaluator.Open(); //Ensure no long jump out of this try
block.
sEvaluator.eval("stop()");
//exception will be thrown because of "stop()".
nTest = -1;
}
catch(CSPexception&
e)
{
e.Print();
nTest = 1;
}
catch(...)
{
}
//Here
nTest == 1
CSPevaluator
Overview | Class Members | Hierarchy chart
CSPevaluator::Close(),
CSPevaluator::IsOpen()
BOOL
Close()
Returns TRUE if it closes the top-level-evaluator successfully else FALSE.
This method closes the top-level-evaluation frame if it is
currently open. It will update all
global C++ objects of class CSPobject to re-attach to global S objects cloned
from the local ones if needed.
The following example demonstrates the use of CSPevaluator::Close()
int nTest = 0;
try
{
//open the top-level-evaluator if it is
not open yet.
CSPevaluator sEvaluator;
//do some long evaluation of S expressions.
sEvaluator.Close(); //Close the
top-level-evaluator and cleanup memory.
sEvaluator.Open(); //Re-open the top-level-evaluator.
//do some more long evaluation of S expressions.
nTest = 1;
}
catch(CSPexception&
e)
{
e.Print();
}
catch(...)
{
}
//Here
nTest == 1
CSPevaluator
Overview | Class Members | Hierarchy chart
CSPevaluator::Open(),
CSPevaluator::IsOpen()
BOOL
IsOpen()
Returns TRUE if top-level-evaluation frame is currently open else FALSE.
This method tests if the top-level-evaluation frame is
currently open.
The following example demonstrates the use of CSPevaluator::IsOpen()
int nTest = 0;
try
{
//open the top-level-evaluator if it is
not open yet.
CSPevaluator sEvaluator;
//do some long evaluation of S expressions.
sEvaluator.Close(); //Close the
top-level-evaluator and cleanup memory.
sEvaluator.Open(); //Re-open the top-level-evaluator.
//do some more long evaluation of S expressions.
nTest = 1;
}
catch(CSPexception&
e)
{
e.Print();
}
catch(...)
{
}
//Here
nTest == 1
CSPevaluator
Overview | Class Members | Hierarchy chart
CSPevaluator::Open(),
CSPevaluator::Close()
BOOL allEqual(s_object*
ps_ object1, s_object* ps_ object2)
BOOL allEqual(CSPobject
sObject1, CSPobject sObject2)
Return TRUE if the contents of the two objects are equal.
|
Parameters |
|
|
ps_object1, ps_object2 |
Pointers to S objects |
|
sObject1, sObject2 |
Objects of class CSPobject or the derived class of
CSPobject |
Use this method to compare contents of two S objects. This method is based on the S function “all.qual”.
The following example demonstrates the use of CSPevaluator::eval()
int nTest=0;
try
{
//open top-level-evaluator if it is not open yet.
CSPevaluator sEvaluator;
//Create the first object from an S expression
CSPnumeric sobj1("1:3");
//Create the second object from a double
array
double x[3]={1.0,
2.0, 3.0};
CSPnumeric
sobj2(x, 3);
//Compare contents
nTest =
sEvaluator.allEqual(sobj1, sobj2) ? 1 : -1;
}
catch(...)
{
}
//Here
nTest == 1
CSPevaluator Overview | Class
Members | Hierarchy
chart
CSPengineConnect::SyncParseEval(),
CSPcall::Eval()

The CSPnumeric class is
similar to the ‘numeric’ class object in the S engine – it is a vector of
doubles. This class supports zero-based
and one-based (Fortran style) indexing into the vector using various bracket
operators on the left-hand and right-hand sides of the equation.
To use CSPnumeric, create
an instance of a CSPnumeric class, and then use the bracket operators to set or
get data.
To support notification in
the client when the object is modified or removed, create a class in the client
which is derived from CSPnumeric.
Override the OnModify() and OnRemove() notification methods in this
class. To use the CSPnumeric-derived
class in the client, create an instance of this derived class. Then call the Create() method to specify a
name for the new object. Finally, use
the bracket operators to set or get data at specific locations in the vector,
or use the assignment operator to copy vectors between different CSPnumeric
objects. After any modifications to the
object in the client program, call the Commit() method to commit these changes
to the S engine object pointed to by this CSPnumeric-derived object. To remove the S engine object pointed to by
this object, call the Remove() method.
Class Members
| Hierarchy
chart
Required includes:
#include "spnum.h"
Samples:
See Also:
CSPcharacter class
overview, CSPinteger class overview, Client-To-Engine connection classes
|
|
|
|
|
Constructs a CSPnumeric object in various ways. |
|
Creates a named ‘numeric’ object in the S engine. |
|
|
Determines if the s_object that this object represents
is valid. |
|
|
|
|
|
Returns a string representing the object name. |
|
|
Returns the number of elements in the vector. |
|
|
Sets an element(s) directly into the vector without
committing to the S database. |
|
|
|
|
|
Assign one CSPnumeric to another by attaching the
s_object member pointer and incrementing the reference count by 1. |
|
|
Zero-based (C style) indexing for left-hand or
right-hand side indexing into the vector. |
|
|
One-based (Fortran style) indexing for left-hand or
right-hand side indexing into the vector. |
|
|
Adds the elements of two CSPnumeric objects to create a
new CSPnumeric object. |
|
|
Subtracts the elements of two CSPnumeric objects to
create a new CSPnumeric object. |
|
|
Multiplies the elements of two CSPnumeric objects to
create a new CSPnumeric object. |
|
|
Divides the elements of two CSPnumeric objects to create
a new CSPnumeric object. |
|
|
|
|
|
Returns the absolute value of the elements of the
vector. |
|
|
Returns the minimum value of all the elements of the
vector. |
|
|
Returns the maximum value of all the elements of the
vector. |
|
|
|
|
|
Commits the modified object to the database. |
|
|
Removes the object from the database. |
|
|
Called when the object is modified. |
|
|
Called when the object is removed. |
|
CSPNumeric Overview
| Hierarchy chart
CSPnumeric(long lLength)
CSPnumeric(double* pdValues,
long lLength)
|
Parameters |
|
|
lLength |
Vector length. |
|
pdValues |
Pointer to an existing array of double. |
Use the constructor with the ‘lLength’ parameter if you
need to create a CSPnumeric object and initialize it with length ‘lLength’.
Use the constructor with ‘pdValues’ and ‘lLength’
parameters if you need to create a CSPnumeric object and initialize it with
data pointed by pdValues with length specified by lLength.
The following example demonstrates the use of CSPnumeric::CSPnumeric(lLength)
int
nTest=0;
try
{
//open
top-level-evaluator if it is not open yet.
CSPevaluator
sEvaluator;
//Create
an S object from
an S expression
CSPnumeric sobj1("numeric(3)");
//Create an S object of length 3
CSPnumeric sobj2(3L);
//Compare contents
nTest = sEvaluator.allEqual(sobj1, sobj2)
? 1 : -1;
}
catch(...)
{
}
//Here nTest == 1
The following example demonstrates the use of
CSPnumeric::CSPnumeric(pdValues, lLength)
int
nTest=0;
try
{
//open
top-level-evaluator if it is not open yet.
CSPevaluator sEvaluator;
//Create
an S object from
an S expression
CSPnumeric sobj1("1:3");
//Create an S object of length 3 from an
array of double
double pdValues[3]={1.0, 2.0, 3.0};
CSPnumeric sobj2(pdValues, 3);
//Compare contents
nTest = sEvaluator.allEqual(sobj1, sobj2)
? 1 : -1;
}
catch(...)
{
}
//Here nTest == 1
CSPNumeric Overview
| Class
Members | Hierarchy chart
virtual BOOL Create(
const char* pszName = NULL, //
object name
const char* pszExpression = NULL, // expression to
initialize data
long lDataBase = 1 ) //
database position
|
Parameters |
|
|
pszName |
Name of the object to create. |
|
pszExpression |
Optional S syntax to evaluate and assign the result of
to the newly created object. |
|
lDataBase |
Database position to assign the newly created object to. |
Returns TRUE if object was successfully created, or FALSE if not.
First construct a CSPnumeric object. Then, use this method to create a named object and initialize it if needed with the result of an expression evaluation.
To support notification in the client when the object is modified or removed, create a class in the client which is derived from CSPnumeric. Override the OnModify() and OnRemove() notification methods in this class. To use the CSPnumeric-derived class in the client, create an instance of this derived class. Then call the Create() method to specify a name for the new object.
In the following example, a new CSPnumeric-derived class
instance is created and the Create() method is called to name and initialize
the object. The class CSPmyNumeric is
implemented in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
BOOL IsValid(void) const
Returns TRUE if the s_object member is valid, or FALSE if not.
Every CSPobject-derived object contains a member s_object pointer that the CSPobject represents in the client program. This member can become invalid if the s_object is removed from the S engine, or it is detached from the CSPobject. This method allows the client program to tell whether the member is valid or not.
In the following example, a new CSPnumeric-derived class instance is created and the Create() method is called to name and initialize the object. IsValid() is called and it returns TRUE. Then the s_object is removed using the Remove() method. IsValid() is called again and it returns FALSE. The class CSPmyNumeric is implemented in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
//
Check whether the s_object is valid (it is)
BOOL
bIsValidBefore = myNumeric.IsValid();
if
( bIsValidBefore ==
FALSE )
{
// Print error in the client
}
//
Remove this object from the S engine database.
//
After this call, the CSPmyNumeric::OnRemove()
//
method will be called in this client program.
if
( !myNumeric.Remove() )
{
// Print error in client
}
//
Check whether the s_object is valid (it is NOT)
BOOL
bIsValidAfter = myNumeric.IsValid();
if
( bIsValidAfter ==
TRUE )
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::CSPnumeric(),
CSPnumeric::Create(), CSPnumeric::Remove()
const CSPnumeric&
operator = (const CSPnumeric& sobject)
This operator will generate an exception in the client upon assignment failure or failure to coerce the right-hand side CSPnumeric object to a ‘numeric’ S engine type.
The assignment operator decrements the reference count on the s_object that the left-hand side CSPnumeric object represents. Then it attaches the s_object of the right-hand side CSPnumeric object to the left-hand side CSPnumeric object. The reference count of the s_object is incremented by 1 during this assignment.
In the following example, a new CSPnumeric-derived class
instance is created and the Create() method is called to name and initialize
the object. Then another CSPmyNumeric
object is created and the first is assigned to the second. The class CSPmyNumeric is implemented in the
client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( NULL, "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
try
{
myNumeric2 = myNumeric;
}
catch(...)
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator ()
virtual double operator []
(int n)
This operator will generate an exception in the client if the index is out of range or the s_object represented by the CSPnumeric object is invalid.
You can think of a CSPnumeric object as an array of
doubles. The overloaded subscript [] operator returns a single double
specified by the zero-based index in
n.
This operator can also be used to assign a double to a particular index
in the array.
The major difference between this operator and the () operator, is that this operator is
zero-based, the other is one-based.
In the following example, two CSPnumeric-derived class
instances are created and the Create() method is called to name and initialize
each. Then the [] operator is used to
get a double from one and assign it into an index in the other. The class CSPmyNumeric is implemented in the
client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( "11:20", "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
try
{
// Copy fourth double from 'myNumeric' to
// second position in 'myNumeric2'
myNumeric2[1] = myNumeric[3];
}
catch(...)
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator (), CSPnumeric::operator =, CSPnumeric::SetAtDirect()
virtual double operator ()
(long n)
This operator will generate an exception in the client if the index is out of range or the s_object represented by the CSPnumeric object is invalid.
You can think of a CSPnumeric object as an array of
doubles. The overloaded subscript () operator returns a single double
specified by the one-based index in n.
This operator can also be used to assign a double to a particular index
in the array.
The major difference between this operator and the [] operator, is that this operator is
one-based, the other is zero-based.
In the following example, two CSPnumeric-derived class
instances are created and the Create() method is called to name and initialize
each. Then the () operator is used to
get a double from one and assign it into an index in the other. The class CSPmyNumeric is implemented in the
client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( "11:20", "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
try
{
// Copy third double from 'myNumeric' to
// first position in 'myNumeric2'
myNumeric2(1) = myNumeric(3);
}
catch(...)
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator =, CSPnumeric::SetAtDirect()
CSPnumeric
CSPnumeric::operator+(const CSPnumeric& sRhs)
This operator will generate an exception in the client if either the left-hand side or right-hand side CSPnumeric object is invalid.
This operator clones the left-hand side object and
iterates through each element up to the last index of the shortest object. For each element, the operator adds the
right-hand side element to the left-hand side element. The cloned object with the result of this
operator on each element is returned.
In the following example, two CSPnumeric-derived class
instances are created and the Create() method is called to name and initialize
each. Then the + operator is used to
add the two (element-by-element) and assign the result to a third object. The class CSPmyNumeric is implemented in the
client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "11:20", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( "1:10", "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
// Add each element of 'myNumeric2'
to
// each element of 'myNumeric'
CSPmyNumeric
myNumeric3 = myNumeric + myNumeric2;
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator =, CSPnumeric::operator -, CSPnumeric::operator *, CSPnumeric::operator /
CSPnumeric
CSPnumeric::operator-(const CSPnumeric& sRhs)
This operator will generate an exception in the client if either the left-hand side or right-hand side CSPnumeric object is invalid.
This operator clones the left-hand side object and
iterates through each element up to the last index of the shortest object. For each element, the operator subtracts the
right-hand side element to the left-hand side element. The cloned object with the result of this
operator on each element is returned.
In the following example, two CSPnumeric-derived class
instances are created and the Create() method is called to name and initialize
each. Then the - operator is used to
subtract the two (element-by-element) and assign the result to a third
object. The class CSPmyNumeric is implemented
in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "11:20", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( "1:10", "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
// Subtract each element of
'myNumeric2' from
// each element of 'myNumeric'
CSPmyNumeric
myNumeric3 = myNumeric - myNumeric2;
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator =, CSPnumeric::operator +, CSPnumeric::operator *, CSPnumeric::operator /
CSPnumeric
CSPnumeric::operator*(const CSPnumeric& sRhs)
This operator will generate an exception in the client if either the left-hand side or right-hand side CSPnumeric object is invalid.
This operator clones the left-hand side object and
iterates through each element up to the last index of the shortest object. For each element, the operator multiplies
the left-hand side element by the right-hand side element. The cloned object with the result of this
operator on each element is returned.
In the following example, two CSPnumeric-derived class
instances are created and the Create() method is called to name and initialize
each. Then the * operator is used to
multiply the two (element-by-element) and assign the result to a third
object. The class CSPmyNumeric is
implemented in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "11:20", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( "1:10", "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
// Multiply each element of
'myNumeric' by
// each element of 'myNumeric2'
CSPmyNumeric
myNumeric3 = myNumeric * myNumeric2;
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator =, CSPnumeric::operator +, CSPnumeric::operator -, CSPnumeric::operator /
CSPnumeric
CSPnumeric::operator/(const CSPnumeric& sRhs)
This operator will generate an exception in the client if either the left-hand side or right-hand side CSPnumeric object is invalid.
This operator clones the left-hand side object and
iterates through each element up to the last index of the shortest object. For each element, the operator divides the
left-hand side element by the right-hand side element. The cloned object with the result of this
operator on each element is returned.
In the following example, two CSPnumeric-derived class
instances are created and the Create() method is called to name and initialize
each. Then the / operator is used to
divide the two (element-by-element) and assign the result to a third
object. The class CSPmyNumeric is implemented
in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "11:20", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
CSPmyNumeric
myNumeric2;
if
( myNumeric2.Create( "1:10", "MyNumeric2" ) != TRUE )
{
// Print error in the client
}
// Divide each element of 'myNumeric'
by
// each element of 'myNumeric2'
CSPmyNumeric
myNumeric3 = myNumeric / myNumeric2;
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator =, CSPnumeric::operator +, CSPnumeric::operator -, CSPnumeric::operator *
CSPnumeric abs( BOOL
bValidate=TRUE ) const
|
Parameters |
|
|
bValidate |
If TRUE, will check whether this object is valid and
generate an exception if not.
Validity check can be slow, so specify FALSE if the object is known to
be valid. |
Returns a CSPnumeric object representing the absolute value of each element in this object.
This operator will generate an exception in the client if this CSPnumeric object is invalid.
This operator clones this object and iterates through each
element. For each element, the operator
sets the absolute value. The cloned
object with the result of this operator on each element is returned.
In the following example, a CSPnumeric-derived class
instances is created and the Create() method is called to name and initialize
each. Then the abs() method is used to
return the absolute values in a third object.
The class CSPmyNumeric is implemented in the client and derived from
CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "-10:-1", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
// Take absolute value of each
element in 'myNumeric'
// and return in new CSPmyNumeric
object
CSPmyNumeric
myNumeric2 = myNumeric.abs();
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::operator [], CSPnumeric::operator =, CSPnumeric::operator +, CSPnumeric::operator -, CSPnumeric::operator *, CSPnumeric::operator /
double Min( BOOL bValidate
= TRUE ) const
|
Parameters |
|
|
bValidate |
If TRUE, will check whether this object is valid and
generate an exception if not.
Validity check can be slow, so specify FALSE if the object is known to
be valid. |
Returns a double representing the minimum value of all the elements in this object.
This operator will generate an exception in the client if this CSPnumeric object is invalid.
In the following example, a CSPnumeric-derived class instances
is created and the Create() method is called to name and initialize each. Then the Min() method is used to return the
minimum value in a double. The class
CSPmyNumeric is implemented in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
double minValue = 0;
try
{
// Return the minimum element of myNumeric
minValue = myNumeric.Min();
}
catch(...)
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(), CSPnumeric::Max()
double Max( BOOL bValidate
= TRUE ) const
|
Parameters |
|
|
bValidate |
If TRUE, will check whether this object is valid and
generate an exception if not.
Validity check can be slow, so specify FALSE if the object is known to
be valid. |
Returns a double representing the maximum value of all the elements in this object.
This operator will generate an exception in the client if this CSPnumeric object is invalid.
In the following example, a CSPnumeric-derived class
instances is created and the Create() method is called to name and initialize
each. Then the Max() method is used to
return the maximum value in the vector.
The class CSPmyNumeric is implemented in the client and derived from
CSPnumeric.
CSPmyNumeric myNumeric;
if
( myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
double maxValue = 0;
try
{
// Return the maximum element of myNumeric
maxValue = myNumeric.Max();
}
catch(...)
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
CSPnumeric::Create(),
CSPnumeric::Min()
virtual const char*
GetObjectName(void) const
Returns a string representing the name of this object.
This function will return NULL if the object is invalid or has no name.
In the following example, a CSPnumeric-derived class
instance is created and the Create() method is called to name and initialize
it. Then the GetObjectName() method is
used to return the name of the object.
The class CSPmyNumeric is implemented in the client and derived from
CSPnumeric.
CSPmyNumeric
myNumeric;
if ( myNumeric.Create( "1:10",
"MyNumeric" ) != TRUE )
{
//
Print error in the client
}
char *pszName = NULL;
try
{
//
Get the name of myNumeric
//
//
NOTE: Make a copy of the char * returned
//
by GetObjectName() before modifying it.
pszName
= (char *)myNumeric.GetObjectName();
if ( !pszName || !*pszName )
throw
"Failed";
//
Print out pszName in
the client
}
catch(...)
{
//
Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
long length( BOOL
bValidate = TRUE ) const
|
Parameters |
|
|
bValidate |
If TRUE, will check whether this object is valid and generate
an exception if not. Validity check
can be slow, so specify FALSE if the object is known to be valid. |
Returns a long representing the number of elements in this object.
This operator will generate an exception in the client if this CSPnumeric object is invalid.
In the following example, a CSPnumeric-derived class
instance is created and the Create() method is called to name and initialize
it. Then the length() method is used to
return the number of elements in the vector.
The class CSPmyNumeric is implemented in the client and derived from
CSPnumeric.
CSPmyNumeric
myNumeric;
if ( myNumeric.Create("1:10",
"MyNumeric" ) != TRUE )
{
// Print error in the client
}
long theLength = 0;
try
{
// Return the length of myNumeric
theLength = myNumeric.length();
if ( theLength != 10 )
throw "Failed";
}
catch(...)
{
// Print error in the client
}
CSPnumeric Overview
| Class
Members | Hierarchy chart
void SetAtDirect(int
nIndex, double dElement, BOOL bValidate=TRUE);
void SetAtDirect(double*
pdValues, long lStartIndex, long lEndIndex,
BOOL
bValidate=TRUE);
|
Parameters |
|
|
nIndex |
The zero-based index to set the value at in the vector. |
|
dElement |
The double value to set. |
|
bValidate |
If TRUE, will check whether this object is valid and
generate an exception if not.
Validity check can be slow, so specify FALSE if the object is known to
be valid. |
|
pdValues |
An array of double values to set which MUST be at least
as long as (lEndIndex-lStartIndex+1). |
|
lStartIndex |
The starting index in the vector (zero-based) to begin
setting elements from the array pdValues. |
|
lEndIndex |
The ending index in the vector (zero-based) to stop
setting elements from the array pdValues. |
This method will generate an exception in the client if lStartValue or lEndIndex are invalid indicies for the CSPnumeric it is called on. The CSPnumeric you call this method on must be at least long as (lEndIndex-lStartIndex+1).
This method will set the value(s) specified by dElement or the array pdValues into the CSPnumeric vector you call it on. If you specify an array of doubles (pdValues), this array must be at least as long as (lEndIndex-lStartIndex+1).
The method directly sets values in the vector of the CSPnumeric. It changes the memory associated with the vector elements, but it does not commit the changed elements to the S database. You must call Commit() to commit the changed values to the CSPnumeric vector in the S database.
In the following example, a new CSPnumeric-derived class
instance is created and the Create() method is called to name and initialize
the object. Then elements are set using
the two forms of SetAtDirect. The class
CSPmyNumeric is implemented in the client and derived from CSPnumeric.
CSPmyNumeric myNumeric;
if (
myNumeric.Create( "1:10", "MyNumeric" ) != TRUE )
{
// Print error in the client
}
double
newValue = 66;
double
newArray[] = { 77, 88, 99 };
try
{
// Modify one of the values in the vector
directly
myNumeric.SetAtDirect( 2, newValue );
// Modify a range of elements in the
vector with
// the values of the array 'newArray'.
myNumeric.SetAtDirect( newArray, 6, 8 );
// Commit this object to database one.
After this
// call, the CSPmyNumeric::OnModify()
method will be
// called in this client program.
myNumeric.Commit();
}
catch(...)
{
// Print error in the client
}