I'm working on a linear data layout where components are alongside each other in memory. Things were going ok until I realized I don't have a way for making offsetof and changetype calls when dealing with nested classes.
For instance, this works as intended:
class Vec2{
x:u8
y:u8
}
const size = offsetof<Vec2>() // 2 -- ok
const ptr = heap.alloc(size)
changeType<Vec2>(ptr).x = 7 // memory = [7,0] -- ok
Naturally this approach fails when nesting classes
class Player{
position:Vec2
health:u8
}
const size = offsetof<Player>() //5 -- want 3, position is a pointer
const ptr = heap.alloc(size)
changeType<Player>(ptr).position.x = 7 //[0,0,0,0,0] -- want [7,0,0], instead accidentally changed pointer 0
The goal is for the memory layout to look like this:
| Player 1 | Player 2 | ...
| x y z h | x y z h |
Ideally I'd love to be able to create 'value-type' fields, or if this isnt a thing, are there alternative approaches?
I'm hoping to avoid extensive boilerplate whenever writing a new component, ie manual size calculation and doing a changetype for each field at its offset etc.
In case anybody is interested I'll post my current solution here. The implementation is a little messy but is certainly automatable using custom scripts or compiler transforms.
Goal: Create a linear proxy for the following class so that the main function behaves as expected:
class Foo {
position: Vec2
health: u8
}
export function main(): Info {
const ptr = heap.alloc(FooProxy.size)
const foo = changetype<FooProxy>(ptr)
foo.health = 3
foo.position.x = 9
foo.position.y = 10
}
Solution: calculate offsets and alignments for each field.
class TypeMetadataBase{
get align():u32{return 0}
get offset():u32{return 0}
}
class TypeMetadata<T> extends TypeMetadataBase{
get align():u32{return alignof<T>()}
get offset():u32{return offsetof<T>()}
constructor(){
super()
if(this.offset == 0)
throw new Error('offset shouldnt be zero, for primitive types use PrimitiveMetadata')
}
};
class PrimitiveMetadata<T> extends TypeMetadataBase{
get align():u32{return sizeof<T>()}
get offset():u32{return sizeof<T>()}
};
class LinearSchema{
metadatas:StaticArray<TypeMetadataBase>
size:u32
offsets:StaticArray<u32>
constructor(metadatas:StaticArray<TypeMetadataBase>){
let align:u32 = 0
const offsets = new StaticArray<u32>(metadatas.length)
for (let i = 0; i < metadatas.length; i++){
if(metadatas[i].align !== 0)
while(align % metadatas[i].align !== 0)
align++
offsets[i] = align
align += metadatas[i].offset
}
this.offsets = offsets
this.metadatas = metadatas
this.size = align
}
}
class Vec2 {
x: u8
y: u8
}
class FooSchema extends LinearSchema{
constructor(){
super([
new PrimitiveMetadata<u8>(),
new TypeMetadata<Vec2>(),
])
}
}
const schema = new FooSchema()
class FooProxy{
static get size():u32{return schema.size}
set health(value:u8){store<u8>(changetype<usize>(this) + schema.offsets[0],value)}
get health():u8{return load<u8>(changetype<usize>(this) + schema.offsets[0])}
get position():Vec2{return changetype<Vec2>(changetype<usize>(this) + schema.offsets[1])}
}
i have question, how to do something like a trigger in Intersystems Cache.
Situation:
for example i have table X with properties(columns)
valueA,valueB
i Want to update valueB when valueA changed by UPDATE. I have define global variable ^VALUEBGENER and use to increment it $SEQ function,
My Idea was:
Class User.X Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {_SYSTEM}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = X]
{
Property VALUEA As %Library.String(MAXLEN = 8) [ Required,SqlColumnumber = 1];
Property VALUEB As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ Required,SqlColumnNumber = 1,SqlComputed,SqlColumnumber = 2, SqlComputeCode = {SET {valueB}=$SEQ(^VALUEBGENER)}, SqlComputeOnChange = %%UPDATE];
}
but it's doesnt work, when i change valuea but it works when i change valueb so, any idea?
P.S. Sorry for bad english
Can do it by adding a trigger, and SqlCompute
Class User.X Extends %Persistent [ ClassType = persistent, DdlAllowed, Final, Owner = {_SYSTEM}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = X]
{
Property VALUEA As %Library.String(MAXLEN = 8) [ Required, SqlComputed,SqlColumnumber = 1];
Property VALUEB As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ Required,InitialExpression=0,SqlColumnNumber = 2, SqlComputeCode = {SET {*}=$SEQ(^VALUEB)}, SqlComputeOnChange = %%UPDATE ];
Trigger[Event=Update]{
NEW valuebx
new rowid
set rowid={ID}
SET valuebx= 0
// {fieldname*C} evaluates to 1 if the field has been changed and 0
if({VALUEA*C}=1){
// we trigger sql computeCode and inc of global variable by update
//and it doesnt matter what is here in :valuebx
&sql(update x set valueb=:valuebx WHERE ROWID=:rowid)
}
}
}
The directions in this section of code are giving me trouble and I don't know how to follow through with them properly. (We have to write code where there are dollar signs.)
Instructions: write a code that repetitively invokes the HashPerformanceClass mainDriver. Then the repetitive code starts the number of insertions at statrInsertions, increase the insert count by the deltaInsertions until end insertions value.
Problem
I am having trouble repetitively invoking the HashPerformanceClass mainDriver, and I don't know what to do. If anyone has any advise I would be grateful.
public class MainClass {
static int displayResultsNo = 0;
void displayHashResults() {
displayResultsNo++;
System.out.println("\nDisplay No. - "+displayResultsNo);
System.out.println("\n\nHash Instrumented Performance:\n-----------------------------");
System.out.println("Trials: " + HashPerformanceClass.trials + ", " +
"Insert Count: " + HashPerformanceClass.insertCount + ", " +
"Load: " + HashPerformanceClass.payload + ", " +
"Table Start Size: " + HashPerformanceClass.startingSize);
System.out.println("\nLinear Hashing:");
System.out.println("Insertion Total Probes: " + HashPerformanceClass.insertionLinearProbes) ;
System.out.println("Insertion Average Probes: " + HashPerformanceClass.insertionLinearProbesAvg);
System.out.println("\nDouble Hashing:");
System.out.println("Insertion Total Probes: " + HashPerformanceClass.insertionDoubleProbes) ;
System.out.println("Insertion Average Probes: " + HashPerformanceClass.insertionDoubleProbesAvg);
System.out.println("\nPerfect Hashing:");
System.out.println("Insertion Total Probes: " + HashPerformanceClass.insertionPerfectProbes) ;
System.out.println("Insertion Average Probes: " + HashPerformanceClass.insertionPerfectProbesAvg);
}//displayHashResults()
static int displayNo = 0;
void displayHashAvgProbesTable(int trials, int startInsertions, int endInsertions, int deltaInsertions, double load, int startSize) {
displayNo++;
System.out.println("\n\nDisplay No. - "+displayNo);
System.out.println("\nAverage Number of Probes Table \n------------------------------\ntrials: "+trials+" Load: "+load+" Start Size: "+startSize+"\n");
System.out.println(String.format("%-15s %-15s %-15s %-15s", "No Of Items","Linear Hash" ,"Double Hash" ,"Perfect Hash ") );
System.out.println(String.format("%-15s %-15s %-15s %-15s", "Inserted" ,"Probe Average","Probe Average","Probe Average") );
System.out.println(String.format("%-15s %-15s %-15s %-15s", "-----------","-------------","-------------","-------------") );
//$ write a code that repetitively invokes the HashPerformanceClass mainDriver
// The the repetitive code starts the number of insertions at startInsertions, increases the insert count by the deltaInsertions
//until end insertions value
}//displayHashAvgProbesTable()
MainClass () {
//$Invoke HashPerformanceClass mainDriver using arguments of insertCount=1, trials =10, payLoad=100%, Starting Size =7, display results
HashPerformanceClass.mainDriver( 1, 1, 1.0, 7); displayHashResults();
HashPerformanceClass.mainDriver(100, 80, 0.5, 101); displayHashResults(); //third column 1.0 = 100%
HashPerformanceClass.mainDriver(100, 80, 0.9, 101); displayHashResults();
HashPerformanceClass.mainDriver( 20, 1000, 0.5, 503); displayHashResults();
HashPerformanceClass.mainDriver( 20, 1000, 1.0, 1009); displayHashResults();
HashPerformanceClass.mainDriver( 20, 1000, 1.0, 4999); displayHashResults();
HashPerformanceClass.mainDriver(100, 2400, 0.5, 4999); displayHashResults();
displayHashAvgProbesTable ( 10, 100, 2000, 100, 0.5, 1009);
displayHashAvgProbesTable ( 10, 100, 2500, 1000, 0.5, 4999);
displayHashAvgProbesTable ( 10, 100, 2500, 1000, 0.5, 4999);
}//MainClass
public static void main(String[] args) {
new MainClass();
}//main()
}//MainClass
___________________________________________________________
import java.util.*;
/**
* A class for generating statistical information hash table insertion.
*/
public class HashPerformanceClass {
static int insertionLinearProbes = 0, insertionDoubleProbes = 0, insertionPerfectProbes = 0;
static float insertionLinearProbesAvg = 0, insertionDoubleProbesAvg = 0, insertionPerfectProbesAvg = 0;
static int trials;
static int insertCount;
static double payload;
static int startingSize;
public static void mainDriver(int trials, int insertCount, double payLoad, int startingSize) {
HashPerformanceClass.trials = trials;
HashPerformanceClass.insertCount = insertCount;
HashPerformanceClass.payload = payLoad;
HashPerformanceClass.startingSize= startingSize;
insertionLinearProbes = insertionDoubleProbes = insertionPerfectProbes = 0;
insertionLinearProbesAvg = insertionDoubleProbesAvg = insertionPerfectProbesAvg = 0;
//$ Declare all 3 hash table objects (linear, double, perfect) using the generic parameterized types as String and setting Starting Size from the mainDriver input parameter
DictionaryInstrumentedLinearImplementation <String, String> linearHashTableObj;
DictionaryInstrumentedDoubleImplementation <String, String> doubleHashTableObj;
DictionaryInstrumentedPerfectImplementation<String, String> perfectHashTableObj;
//Array used to hold random data inserted
String dataArray[];
//$
//For each trial set the inputs for the hash table Implementation
// Generate the Random Data array using insert count, do only once for each trial so that all hash table types have same source data set
// For all 3 hash table types
// Instantiate new hash table object
// Set the pay load factor hashtableobject.set payload
// Insert all the data from the array into the table insertalldata( , );
// Reset the probe counters for the hash table insertionlinear probes +=
// Sum up the probe statistics
//do this for all insertionlinearprobes double and perfect . . .
//$ Calculate all the insertion probes averages into the class variables for each hash type
}//mainDriver()
/* Generate an array of random of pseudo words. Each word will be composed of three randomly chosen syllables.
* #param arraySize The number of strings to generate.
* #return The array of strings.
*/
private static String[] generateRandomData(int arraySize) {
String uniqueWordStringArray[] = new String[arraySize];
DictionaryInstrumentedLinearImplementation<String,String> checkTable = new DictionaryInstrumentedLinearImplementation<String,String>();
String firstSylStringArray [] = {"ther", "fal", "sol", "cal", "com", "don", "gan", "tel", "fren", "ras", "tar", "men", "tri", "cap", "har"};
String secondSylStringArray[] = {"mo", "ta", "ra", "te", "bo", "bi", "du", "ca", "dan", "sen", "di", "no", "fe", "mi", "so" };
String thirdSylStringArray [] = {"tion", "ral", "tal", "ly", "nance", "tor", "ing", "ger", "ten", "ful", "son", "dar", "der", "den", "ton"};
Random generator = new Random();
int i=0;
while (i < arraySize) {
String valueString;
valueString = firstSylStringArray [generator.nextInt( firstSylStringArray.length) ];
valueString += secondSylStringArray[generator.nextInt(secondSylStringArray.length) ];
valueString += thirdSylStringArray [generator.nextInt( thirdSylStringArray.length) ];
if (!checkTable.contains(valueString)) {
// Have not seen pseudo word string before, so add it to the list array list
uniqueWordStringArray[i] = valueString;
checkTable.add(valueString,valueString);
i++;
}//end if
}//while
return uniqueWordStringArray;
}
/* Insert all of the values in the array into the hash table.
* #param dict The dictionary to insert all the words into.
*/
private static void insertAllData(DictionaryInterface<String,String> dict, String[] dataArray) {
for (String wordString : dataArray) {
dict.add(wordString, wordString);
}
}//insertAllData()
}//HashPerformanceClass
I'm trying to access instance variables from within a nested object ('action'). The only workaround I could find was using a local var ('_') to represent the parent object.
Class Mover
...
Constructor () =>
_ = this
#mode = "wave"
#action= {
wave: ->
_.x = _.ox
_.y = _.oy = Math.cos(window.G.time * _.speed + _.c + _.vary) * _.amp - _.amp * .5
return
jump: ->
_.y = _.oy = Math.min(0,Math.cos(window.G.time*_.speed + _.c * _.vary)) * _.amp - _.amp * .5
_.x = _.ox
return
#loop =>
#action[#mode]()
Try using a fat arrow (=>) inside your action object like so:
wave: =>
#x = #ox
#y = #oy = Math.cos(window.G.time * #speed + #c + #vary) * #amp - #amp * .5
return
List<double> y = new List<double> { 0.4807, -3.7070, -4.5582,
-11.2126, -0.7733, 3.7269,
2.7672, 8.3333, 4.7023 };
List<double> d1 = y.ForEach(i => i * 2);
Error: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
What is wrong?
Thanks
List<T>.ForEach doesn't perform a conversion: it executes the given delegate for each item, but that's all. That's why it has a void return type - and why the parameter type is Action<T> rather than something like Func<T, TResult>. This last part is why you've got a compilation error. You're basically trying to do:
Action<double> = i => i * 2;
That will give you the same compilation error.
If you want to stick within the List<T> methods (e.g. because you're using .NET 2.0) you can use List<T>.ConvertAll:
List<double> d1 = y.ConvertAll(i => i * 2);
Try instead:
List<double> d1 = y.Select(i => i * 2).ToList();
List.Foreach takes an Action<> delegate which does not return anything, so you cannot use it to create a new list that way. As others have pointed out, using ForEach is not the best option here. A sample on how to perform the operation using ForEach might help to understand why:
List<double> y = new List<double> { 0.4807, -3.7070, -4.5582,
-11.2126, -0.7733, 3.7269,
2.7672, 8.3333, 4.7023 };
List<double> d1 = new List<double>();
Action<double> a = i => d1.Add(i*2);
y.ForEach(a);
List<double> d1 = y.ForEach(i => i = i * 2);