TypeFactory.java
/*
** Module : TypeFactory.java
** Abstract : defines APIs to create 4GL-compatible instances and initialize parameters.
**
** Copyright (c) 2016-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 CA 20160721 Created initial version. Added APIs to create 4GL-compatible instances, with
** or without initializers, with or without extent clauses. Also, there are
** APIs to initialize function/procedure parameters.
** 002 SVL 20170126 Added initializer for COM handle type.
** 003 OM 20170807 Added missing methods related to comhandles.
** 004 GES 20181211 Added object methods.
** OM 20181218 Improved generics.
** 005 CA 20190122 Removed deprecated object APIs - all objects must specify their underlying
** type.
** Legacy object instances are constructed as ObjectVar, as only these instances
** will be enable the reference counting on assignment.
** 006 OM 20190626 Added chained-attribute expression error in handle.
** 007 CA 20190719 INPUT parameters must do reference counting always.
** 008 CA 20190927 Added support for direct Java access from 4GL code.
** 009 ME 20201125 Register newly created object array with indeterminate extent as dynamic.
** CA 20210215 An INPUT parameter at the property SETTER, method, procedure r function must be registered
** as pending, so its reference can be tracked.
** ME 20210322 Instantiated object arrays are not registered as pending, also register handle arrays.
** CA 20210609 Reworked INPUT/INPUT-OUTPUT parameters to a new approach, where they are explicitly
** initialized at the method's execution, and not at the caller's arguments.
** CA 20210818 Fixed memptr parameter runtime - they share the 'pointer structure' with the passed
** argument.
** VVT 20210917 Javadoc fixed.
** CA 20220120 Allow OO vars to be registered as pending, at their definition.
** CA 20220901 Refactored scope notification support: ScopeableFactory was removed, and the registration
** is now specific to each type of scopeable. For each case, the block will be registered
** for scope support (for that particular scopeable) only when the scopeable is 'active'
** (i.e. unnamed streams or accumulators are used). This allows a lazy registration of
** scopeables, to avoid the unnecessary overhead of processing all the scopeables for each
** and every block.
** CA 20230116 Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD runtime.
** 010 CA 20230712 Added support for 'jobject' extent variables, emitted for Java-style arrays used in 4GL
** code.
** 011 CA 20230817 Removed ObjectOps.register, as this registration is handled by runtime.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
import com.goldencode.p2j.oo.lang.*;
import java.util.function.Function;
/**
* Provides APIs to create or initialize or 4GL-compatbile instance.
*/
public class TypeFactory
{
/** Function to create and initialize a {@link date} instance. */
private static Function<date, date> DATE_INIT = (d) -> (new date(d));
/** Function to create and initialize a {@link datetime} instance. */
private static Function<datetime, datetime> DATETIME_INIT = (d) -> (new datetime(d));
/** Function to create and initialize a {@link datetimetz} instance. */
private static Function<datetimetz, datetimetz> DATETIMETZ_INIT = (d) -> (new datetimetz(d));
/** Function to create and initialize a {@link logical} instance. */
private static Function<Boolean, logical> BOOLEAN_INIT = (d) -> (d == null ? new logical()
: new logical(d));
/** Function to create and initialize a {@link decimal} instance. */
private static Function<decimal, decimal> DECIMAL_INIT = (d) -> (new decimal(d));
/** Function to create and initialize a {@link integer} instance. */
private static Function<Long, integer> INTEGER_INIT = (d) -> (d == null ? new integer()
: new integer(d));
/** Function to create and initialize a {@link int64} instance. */
private static Function<Long, int64> INT64_INIT = (d) -> (d == null ? new int64()
: new int64(d));
/** Function to create and initialize a {@link character} instance. */
private static Function<String, character> CHARACTER_INIT = (d) -> (d == null ? new character()
: new character(d));
/** Function to create and initialize a {@link longchar} instance. */
private static Function<String, longchar> LONGCHAR_INIT = (d) -> (d == null ? new longchar()
: new longchar(d));
/** Function to create and initialize a {@link recid} instance. */
private static Function<Long, recid> RECID_INIT = (d) -> (d == null ? new recid()
: new recid(d));
/**
* Initialize an <code>INPUT</code> parameter by creating a deep copy of the specified instance.
*
* @param var
* The original instance receive as an argument.
*
* @return A copy of the given variable.
*
* @see BaseDataType#deepCopy()
*/
public static <T extends BaseDataType> T initInput(T var)
{
T newVar = null;
// this needs to create a ObjectVar
if (var instanceof object)
{
if (ObjectOps.isValid(((object) var).ref))
{
newVar = (T) new ObjectVar(((object) var).type());
newVar.assign(var);
}
else
{
// TODO: we need to emit at the conversion the parameter's OO type (as it gets lost if
// an INPUT is sent).
newVar = (T) var.deepCopy();
}
ObjectOps.registerPending(newVar);
}
else if (var instanceof memptr)
{
memptr m = new memptr();
m.asParameter((memptr) var);
newVar = (T) m;
}
else
{
newVar = (T) var.deepCopy();
}
return newVar;
}
/**
* Initialize an <code>INPUT</code> extent parameter by creating a deep copy of the specified
* array.
*
* @param var
* The original array instance receive as an argument.
*
* @return A copy of the given array.
*
* @see ArrayAssigner#copyOf(BaseDataType[])
*/
public static <T extends BaseDataType> T[] initInput(T[] var)
{
if (memptr.class.isAssignableFrom(var.getClass().getComponentType()))
{
memptr[] newVar = new memptr[var.length];
for (int i = 0; i < newVar.length; i++)
{
newVar[i] = new memptr();
newVar[i].asParameter((memptr) var[i]);
}
return (T[]) newVar;
}
// this needs to create a ObjectVar
T[] newVar = ArrayAssigner.copyOf(var);
return newVar;
}
/**
* Initialize an <code>OUTPUT</code> parameter by setting it to its default value.
*
* @param var
* The original instance receive as an argument.
*
* @return The instance to be used at the method's execution.
*/
public static <T extends BaseDataType> T initOutput(T var)
{
return initOutput(true, var);
}
/**
* Initialize an <code>OUTPUT</code> parameter by setting it either to its default value or
* to <code>unknown</code>, depending on the state of the <code>initDefault</code> flag.
*
* @param initDefault
* When <code>true</code>, initialize to default init value, otherwise to unknown.
* @param var
* The original instance receive as an argument.
*
* @return The instance to be used at the method's execution.
*/
public static <T extends BaseDataType> T initOutput(boolean initDefault, T var)
{
T newVar = var.getAssigner() == null ? OutputParameter.wrap(var) : var;
if (!(newVar instanceof memptr))
{
if (initDefault && !(var instanceof ObjectVar))
{
BaseDataType def = var.instantiateDefault();
newVar.assign(def);
}
else
{
newVar.setUnknown();
}
}
// this ensures the assigner is created and registered as pending for the next scope
AbstractSimpleParameter assigner = (AbstractSimpleParameter) newVar.getAssigner().get();
newVar = (T) AbstractParameter.postProcessOutput(assigner, var);
if (newVar instanceof memptr)
{
((memptr) newVar).asParameter((memptr) var);
}
return newVar;
}
/**
* Initialize an <code>OUTPUT</code> parameter by setting it to the specified init value.
*
* @param var
* The original instance receive as an argument.
* @param init
* The init instance.
*
* @return The instance to be used at the method's execution.
*/
public static <T extends BaseDataType> T initOutput(T var, T init)
{
// memptr can't have an INIT option
T newVar = var.getAssigner() == null ? OutputParameter.wrap(var) : var;
newVar.assign(init);
// this ensures the assigner is created and registered as pending for the next scope
AbstractSimpleParameter assigner = (AbstractSimpleParameter) newVar.getAssigner().get();
newVar = (T) AbstractParameter.postProcessOutput(assigner, var);
return newVar;
}
/**
* Initialize an <code>OUTPUT</code> extent parameter.
*
* @param var
* The original instance receive as an argument.
*
* @return The associated array.
*
* @see OutputExtentParameter#initParameter()
*/
public static <T extends BaseDataType> T[] initOutput(OutputExtentParameter<T> var)
{
var.registerParameter();
T[] newVar = var.initParameter();
return newVar;
}
/**
* Initialize an <code>OUTPUT</code> extent parameter using the specified initializer and
* extent value.
*
* @param var
* The original instance receive as an argument.
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return The associated array.
*
* @see #initExtent(BaseDataType[], Object[], Function)
*/
public static <T extends BaseDataType> T[] initOutput(OutputExtentParameter<T> var,
int extent,
T... init)
{
var.registerParameter();
T[] newVar = var.initParameter(extent);
if (extent == 0 || memptr.class.isAssignableFrom(newVar.getClass().getComponentType()))
{
return newVar;
}
if (init == null || init.length == 0)
{
BaseDataType.initializeDefaultExtent(newVar);
}
else
{
T last = init[init.length - 1];
for (int i = 0; i < Math.min(extent, init.length); i++)
{
newVar[i].assign(init[i]);
}
for (int i = init.length; i < extent; i++)
{
newVar[i].assign(last);
}
}
return newVar;
}
/**
* Initialize an <code>OUTPUT</code> parameter by setting it to its default value.
*
* @param var
* The original instance receive as an argument.
*
* @return The instance to be used at the method's execution.
*/
public static <T extends BaseDataType> T initInputOutput(T var)
{
T newVar = var.getAssigner() == null ? OutputParameter.wrap(var, true) : var;
// this ensures the assigner is created and registered as pending for the next scope
AbstractSimpleParameter assigner = (AbstractSimpleParameter) newVar.getAssigner().get();
newVar = (T) AbstractParameter.postProcessOutput(assigner, var);
if (newVar instanceof memptr)
{
((memptr) newVar).asParameter((memptr) var);
}
return newVar;
}
/**
* Initialize an <code>INPUT-OUTPUT</code> extent parameter.
*
* @param var
* The original instance receive as an argument.
*
* @return The associated array.
*
* @see InputOutputExtentParameter#initParameter()
*/
public static <T extends BaseDataType> T[] initInputOutput(InputOutputExtentParameter<T> var)
{
var.registerParameter();
T[] newVar = var.initParameter();
return newVar;
}
/**
* Initialize an <code>INPUT-OUTPUT</code> extent parameter.
*
* @param var
* The original instance receive as an argument.
* @param extent
* The array length.
*
* @return The associated array.
*
* @see InputOutputExtentParameter#initParameter(int)
*/
public static <T extends BaseDataType> T[] initInputOutput(InputOutputExtentParameter<T> var,
int extent)
{
var.registerParameter();
T[] newVar = var.initParameter(extent);
return newVar;
}
/**
* Create a {@link memptr} instance initialized to the default value.
*
* @return See above.
*/
public static memptr memptr()
{
memptr res = new memptr();
return res;
}
/**
* Create a {@link memptr} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
*
* @return See above.
*/
public static memptr[] memptrExtent(int extent)
{
memptr[] res = new memptr[extent];
BaseDataType.initializeDefaultExtent(res);
return res;
}
/**
* Create a 0-length {@link memptr} array.
*
* @return See above.
*/
public static memptr[] memptrExtent()
{
memptr[] res = new memptr[0];
return res;
}
/**
* Create a {@link raw} instance initialized to the default value.
*
* @return See above.
*/
public static raw raw()
{
raw res = new raw();
return res;
}
/**
* Create a {@link raw} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
*
* @return See above.
*/
public static raw[] rawExtent(int extent)
{
raw[] res = new raw[extent];
BaseDataType.initializeDefaultExtent(res);
return res;
}
/**
* Create a 0-length {@link raw} array.
*
* @return See above.
*/
public static raw[] rawExtent()
{
raw[] res = new raw[0];
return res;
}
/**
* Create a {@link date} instance initialized to the default value.
*
* @return See above.
*/
public static date date()
{
date res = new date();
return res;
}
/**
* Create a {@link date} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static date[] dateExtent(int extent, date... init)
{
date[] res = new date[extent];
initExtent(res, init, DATE_INIT);
return res;
}
/**
* Create a {@link date} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static date[] dateExtent(date... init)
{
date[] res = new date[init.length];
initExtent(res, init, DATE_INIT);
return res;
}
/**
* Create a {@link date} instance initialized to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static date date(date init)
{
date res = new date(init);
return res;
}
/**
* Create a {@link datetime} instance initialized to the default value.
*
* @return See above.
*/
public static datetime datetime()
{
datetime res = new datetime();
return res;
}
/**
* Create a {@link datetime} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static datetime[] datetimeExtent(int extent, datetime... init)
{
datetime[] res = new datetime[extent];
initExtent(res, init, DATETIME_INIT);
return res;
}
/**
* Create a {@link datetime} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static datetime[] datetimeExtent(datetime... init)
{
datetime[] res = new datetime[init.length];
initExtent(res, init, DATETIME_INIT);
return res;
}
/**
* Create a {@link datetime} instance initialized to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static datetime datetime(datetime init)
{
datetime res = new datetime(init);
return res;
}
/**
* Create a {@link datetimetz} instance initialized to the default value.
*
* @return See above.
*/
public static datetimetz datetimetz()
{
datetimetz res = new datetimetz();
return res;
}
/**
* Create a {@link datetimetz} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static datetimetz[] datetimetzExtent(int extent, datetimetz... init)
{
datetimetz[] res = new datetimetz[extent];
initExtent(res, init, DATETIMETZ_INIT);
return res;
}
/**
* Create a {@link datetimetz} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static datetimetz[] datetimetzExtent(datetimetz... init)
{
datetimetz[] res = new datetimetz[init.length];
initExtent(res, init, DATETIMETZ_INIT);
return res;
}
/**
* Create a {@link datetimetz} instance initialized to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static datetimetz datetimetz(datetimetz init)
{
datetimetz res = new datetimetz(init);
return res;
}
/**
* Create a generic {@link jobject} instance initialized to the default value.
*
* @param cls
* The class that will be wrapped by this object.
*
* @return See above.
*/
public static <V extends Object> jobject<V> jobject(Class<V> cls)
{
jobject<V> res = new jobject<V>(cls);
ObjectOps.registerPending(res);
return res;
}
/**
* Create an empty {@link jobject} array.
*
* @param cls
* The class that will be wrapped by the objects in this array.
*
* @return See above.
*/
public static <V extends Object> jobject<V>[] jobjectExtent(Class<V> cls)
{
return jobjectExtent(0, cls);
}
/**
* Create an {@link jobject} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
* @param cls
* The class that will be wrapped by the objects in this array.
*
* @return See above.
*/
public static <V extends Object> jobject<V>[] jobjectExtent(int extent, Class<V> cls)
{
jobject<V>[] res = new jobject[extent]; // unchecked warning
for (int i = 0; i < extent; i++)
{
res[i] = new jobject<V>(cls);
}
return res;
}
/**
* Create a generic {@link object} instance initialized to the default value.
*
* @param cls
* The class that will be wrapped by this object.
*
* @return See above.
*/
public static <V extends _BaseObject_> object<V> object(Class<V> cls)
{
object<V> res = new ObjectVar<V>(cls);
ObjectOps.registerPending(res);
return res;
}
/**
* Create an empty {@link object} array (indeterminate EXTENT variable).
*
* @param cls
* The class that will be wrapped by the objects in this array.
* @param register
* Flag indicating if the registration must be done as 'pending' for the next top-level block.
*
* @return See above.
*/
public static <V extends _BaseObject_> object<V>[] objectExtent(Class<V> cls, boolean register)
{
return objectExtent(0, cls, register);
}
/**
* Create an empty {@link object} array (indeterminate EXTENT variable).
*
* @param cls
* The class that will be wrapped by the objects in this array.
*
* @return See above.
*/
public static <V extends _BaseObject_> object<V>[] objectExtent(Class<V> cls)
{
return objectExtent(cls, true);
}
/**
* Create an {@link object} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
* @param cls
* The class that will be wrapped by the objects in this array.
*
* @return See above.
*/
public static <V extends _BaseObject_> object<V>[] objectExtent(int extent, Class<V> cls)
{
return objectExtent(extent, cls, true);
}
/**
* Create an {@link object} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
* @param cls
* The class that will be wrapped by the objects in this array.
* @param register
* Flag indicating if the registration must be done as 'pending' for the next top-level block.
*
* @return See above.
*/
public static <V extends _BaseObject_> object<V>[] objectExtent(int extent, Class<V> cls, boolean register)
{
object<V>[] res = new object[extent]; // unchecked warning
if (extent == 0)
{
ArrayAssigner.registerDynamicArray(res);
ArrayAssigner.setObjectType(res, cls);
}
for (int i = 0; i < extent; i++)
{
res[i] = new ObjectVar<V>(cls);
}
if (register)
{
ObjectOps.registerPending((Object) res);
}
return res;
}
/**
* Create a {@link handle} instance initialized to the default value.
*
* @return See above.
*/
public static handle handle()
{
handle res = new handle(false);
return res;
}
/**
* Create a 0-length {@link handle} array.
*
* @return See above.
*/
public static handle[] handleExtent()
{
return handleExtent(0);
}
/**
* Create a {@link handle} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
*
* @return See above.
*/
public static handle[] handleExtent(int extent)
{
handle[] res = new handle[extent];
if (extent == 0)
{
ArrayAssigner.registerDynamicArray(res);
}
BaseDataType.initializeDefaultExtent(res);
return res;
}
/**
* Create a {@link comhandle} instance initialized to the default value.
*
* @return See above.
*/
public static comhandle comhandle()
{
return new comhandle();
}
/**
* Create a 0-length {@link comhandle} array.
*
* @return See above.
*/
public static comhandle[] comhandleExtent()
{
return new comhandle[0];
}
/**
* Create a 0-length {@link comhandle} array.
*
* @param extent
* array extent
*
* @return See above.
*/
public static comhandle[] comhandleExtent(int extent)
{
comhandle[] res = new comhandle[extent];
BaseDataType.initializeDefaultExtent(res);
return res;
}
/**
* Create a {@link logical} instance initialized to the default value.
*
* @return See above.
*/
public static logical logical()
{
logical res = new logical(false);
return res;
}
/**
* Create a {@link logical} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static logical[] logicalExtent(int extent, Boolean... init)
{
logical[] res = new logical[extent];
initExtent(res, init, BOOLEAN_INIT);
return res;
}
/**
* Create a {@link logical} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static logical[] logicalExtent(Boolean... init)
{
logical[] res = new logical[init.length];
initExtent(res, init, BOOLEAN_INIT);
return res;
}
/**
* Create a {@link logical} instance. If the <code>init</code> is null, initialize it to
* <code>unknown</code>. Otherwise, initialize it to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static logical logical(Boolean init)
{
logical res = (init == null ? new logical() : new logical(init));
return res;
}
/**
* Create a {@link decimal} instance initialized to the default value.
*
* @return See above.
*/
public static decimal decimal()
{
decimal res = new decimal(0);
return res;
}
/**
* Create a {@link decimal} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static decimal[] decimalExtent(int extent, decimal... init)
{
decimal[] res = new decimal[extent];
initExtent(res, init, DECIMAL_INIT);
return res;
}
/**
* Create a {@link decimal} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static decimal[] decimalExtent(decimal... init)
{
decimal[] res = new decimal[init.length];
initExtent(res, init, DECIMAL_INIT);
return res;
}
/**
* Create a {@link decimal} instance initialized to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static decimal decimal(decimal init)
{
decimal res = new decimal(init);
return res;
}
/**
* Create a {@link integer} instance initialized to the default value.
*
* @return See above.
*/
public static integer integer()
{
integer res = new integer(0);
return res;
}
/**
* Create a {@link integer} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static integer[] integerExtent(int extent, Long... init)
{
integer[] res = new integer[extent];
initExtent(res, init, INTEGER_INIT);
return res;
}
/**
* Create a {@link integer} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static integer[] integerExtent(Long... init)
{
integer[] res = new integer[init.length];
initExtent(res, init, INTEGER_INIT);
return res;
}
/**
* Create a {@link integer} instance. If the <code>init</code> is null, initialize it to
* <code>unknown</code>. Otherwise, initialize it to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static integer integer(Long init)
{
integer res = (init == null ? new integer() : new integer(init));
return res;
}
/**
* Create a {@link int64} instance initialized to the default value.
*
* @return See above.
*/
public static int64 int64()
{
int64 res = new int64(0);
return res;
}
/**
* Create a {@link int64} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static int64[] int64Extent(int extent, Long... init)
{
int64[] res = new int64[extent];
initExtent(res, init, INT64_INIT);
return res;
}
/**
* Create a {@link int64} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static int64[] int64Extent(Long... init)
{
int64[] res = new int64[init.length];
initExtent(res, init, INT64_INIT);
return res;
}
/**
* Create a {@link int64} instance. If the <code>init</code> is null, initialize it to
* <code>unknown</code>. Otherwise, initialize it to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static int64 int64(Long init)
{
int64 res = (init == null ? new int64() : new int64(init));
return res;
}
/**
* Create a {@link rowid} instance initialized to the default value.
*
* @return See above.
*/
public static rowid rowid()
{
rowid res = new rowid();
return res;
}
/**
* Create a {@link rowid} array of the given extent and initialize it with the default value.
*
* @param extent
* The array length.
*
* @return See above.
*/
public static rowid[] rowidExtent(int extent)
{
rowid[] res = new rowid[extent];
BaseDataType.initializeDefaultExtent(res);
return res;
}
/**
* Create a 0-length {@link rowid} array.
*
* @return See above.
*/
public static rowid[] rowidExtent()
{
rowid[] res = new rowid[0];
return res;
}
/**
* Create a {@link recid} instance initialized to the default value.
*
* @return See above.
*/
public static recid recid()
{
recid res = new recid();
return res;
}
/**
* Create a {@link recid} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static recid[] recidExtent(int extent, Long... init)
{
recid[] res = new recid[extent];
initExtent(res, init, RECID_INIT);
return res;
}
/**
* Create a {@link recid} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static recid[] recidExtent(Long... init)
{
recid[] res = new recid[init.length];
initExtent(res, init, RECID_INIT);
return res;
}
/**
* Create a {@link recid} instance. If the <code>init</code> is null, initialize it to
* <code>unknown</code>. Otherwise, initialize it to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static recid recid(Long init)
{
recid res = (init == null ? new recid() : new recid(init));
return res;
}
/**
* Create a {@link character} instance initialized to the default value.
*
* @return See above.
*/
public static character character()
{
character res = new character("");
return res;
}
/**
* Create a {@link character} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static character[] characterExtent(int extent, String... init)
{
character[] res = new character[extent];
initExtent(res, init, CHARACTER_INIT);
return res;
}
/**
* Create a {@link character} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static character[] characterExtent(String... init)
{
character[] res = new character[init.length];
initExtent(res, init, CHARACTER_INIT);
return res;
}
/**
* Create a {@link character} instance. If the <code>init</code> is null, initialize it to
* <code>unknown</code>. Otherwise, initialize it to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static character character(String init)
{
character res = (init == null ? new character() : new character(init));
return res;
}
/**
* Create a {@link longchar} instance initialized to the default value.
*
* @return See above.
*/
public static longchar longchar()
{
longchar res = new longchar("");
return res;
}
/**
* Create a {@link longchar} array of the given extent. If there is data in the
* <code>init</code> array for a specified index, that will be used to initialize it.
* Otherwise, if the init array is empty, default initializer will be used; if the init array
* is not empty, all indices which don't have a counterpart will use the last entry in
* this array.
*
* @param extent
* The array length.
* @param init
* The initializer array.
*
* @return See above.
*/
public static longchar[] longcharExtent(int extent, String... init)
{
longchar[] res = new longchar[extent];
initExtent(res, init, LONGCHAR_INIT);
return res;
}
/**
* Create a {@link longchar} extent using as initial values the data in the <code>init</code>
* array. If the init array is empty, a non-initialized (0-extent) array will be returned.
*
* @param init
* The initializer array.
*
* @return See above.
*/
public static longchar[] longcharExtent(String... init)
{
longchar[] res = new longchar[init.length];
initExtent(res, init, LONGCHAR_INIT);
return res;
}
/**
* Create a {@link longchar} instance. If the <code>init</code> is null, initialize it to
* <code>unknown</code>. Otherwise, initialize it to the init value.
*
* @param init
* The init value.
*
* @return See above.
*/
public static longchar longchar(String init)
{
longchar res = (init == null ? new longchar() : new longchar(init));
return res;
}
/**
* Initialize the specified array using; if there is data in the <code>init</code> array for
* a specified index, that will be used to initialize it. Otherwise, if the init array is
* empty, default initializer will be used; if the init array is not empty, all indices which
* don't have a counterpart will use the last entry in this array.
*
* @param res
* The array to be initialized.
* @param init
* The initializer.
* @param finit
* Function which will create either a default value or an initialized value,
* depending on the given argument.
*/
private static <T extends BaseDataType, I> void initExtent(BaseDataType[] res,
I[] init,
Function<I, T> finit)
{
int extent = res.length;
if (extent == 0)
{
ArrayAssigner.registerDynamicArray(res);
return;
}
if (init == null || init.length == 0)
{
BaseDataType.initializeDefaultExtent(res);
}
else
{
I last = init[init.length - 1];
for (int i = 0; i < Math.min(extent, init.length); i++)
{
res[i] = finit.apply(init[i]);
}
for (int i = init.length; i < extent; i++)
{
res[i] = finit.apply(last);
}
}
}
}