Why is the lambda function not copying out the struct? - c++

I'm modifying a code-base to get a struct (TheClipInfo) out of a Lambda so I can return one of it's properties (CurrentFrameCount).
I think I'm passing it by reference, but clearly I'm missing something.
Comments below show where I modified the code.
int32 UTimeSynthComponent::StopClipOffset(FTimeSynthClipHandle InClipHandle, ETimeSynthEventClipQuantization EventQuantization)
{
Audio::EEventQuantization StopQuantization = GlobalQuantization;
if (EventQuantization != ETimeSynthEventClipQuantization::Global)
{
int32 ClipQuantizationEnumIndex = (int32)EventQuantization;
check(ClipQuantizationEnumIndex >= 1);
StopQuantization = (Audio::EEventQuantization)(ClipQuantizationEnumIndex - 1);
}
FPlayingClipInfo TheClipInfo; // I want the Lambda to put data here.
SynthCommand([this, InClipHandle, StopQuantization, &TheClipInfo] // The first Lambda
{
EventQuantizer.EnqueueEvent(StopQuantization,
[this, InClipHandle, &TheClipInfo](uint32 NumFramesOffset) // The Second Lambda
{
int32* PlayingClipIndex = ClipIdToClipIndexMap_AudioRenderThread.Find(InClipHandle.ClipId);
if (PlayingClipIndex)
{
// Grab the clip info
FPlayingClipInfo& PlayingClipInfo = PlayingClipsPool_AudioRenderThread[*PlayingClipIndex]; // The Struct I want to get out.
// Only do anything if the clip is not yet already fading
if (PlayingClipInfo.CurrentFrameCount < PlayingClipInfo.DurationFrames)
{
// Adjust the duration of the clip to "spoof" it's code which triggers a fade this render callback block.
PlayingClipInfo.DurationFrames = PlayingClipInfo.CurrentFrameCount + NumFramesOffset;
}
TheClipInfo = PlayingClipInfo; // I think this should make a copy.
}
});
});
return TheClipInfo.CurrentFrameCount; // This is always returning 0.
}
I'm assuming this is all happening in the same thread and in order (not some async callback like JavaScript).
My first attempt was with an int32, but that can't be passed by reference. I really want just one value from it.

Snap!
EventQuantizer.EnqueueEvent
Adds the second lambda to an event queue. So it is asynch. Which is why it's not working as I'd like.
The simplest thing that could work is to copy the code out of the lambda and use it for the return.

Related

How to get flow output from non flow fuction

I want flow output (return type Flow<T>) from a non-flow function (return typeT).
fun getTotalFiles(): Int
// Say, This is a library function it'll return the number of files (Int) in that folder at that specific moment.
//And,
fun getAllFiles(): List<File>
// Say, This is a library function it'll return all the files (List<File>) in that folder.
The files in that folder can and will change in the future.
Now, I want to constantly observe the output, so how do I implement it?
fun getFlowOfTotalFiles(): Flow<Int> =
// A wrapper function that converts the library function return type to an observable flow, Flow<Int>
//And,
fun getFlowOfAllFiles(): Flow<List<File>> =
// A wrapper function that converts the library function return type to an observable flow, Flow<List<File>>
For specifically monitoring a directory for files, you can use WatchService and convert it to a flow with the flow builder. Something like this:
fun getDirectoryMonitorFlow(directory: String) = flow {
FileSystems.getDefault().newWatchService().use { watchService ->
while (true) {
val watchKey = Path.of(directory).register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY)
if (watchKey.pollEvents().isNotEmpty()) {
emit(Unit)
}
yield() // give flow opportunity to be cancelled.
if (!watchKey.reset()) {
println("Directory became unreadable. Finishing flow.")
break
}
}
}
}
.catch { println("Exception while monitoring directory.") }
.flowOn(Dispatchers.IO)
And then your class might look like:
fun getFlowOfTotalFiles(): Flow<Int> = getFlowOfAllFiles()
.map { it.size }
.distinctUntilChanged()
fun getFlowOfAllFiles(): Flow<List<File>> = flow {
emit(Unit) // so current state is always emitted
emitAll(getDirectoryMonitorFlow(directory))
}
.map {
File(directory).listFiles()?.toList().orEmpty()
}
.flowOn(Dispatchers.IO)
.distinctUntilChanged()
Although you might consider making the first flow a private SharedFlow so you aren't running multiple WatchServices to monitor the same directory concurrently.
I believe you need an infinite loop inside a flow builder, something like the following:
fun getFlowOfTotalFiles(): Flow<Int> = flow {
while (true) {
emit(getTotalFiles())
// delays for 5 sec before next request and
// terminates the infinite cycle when a coroutine,
// that collects this Flow, is canceled
delay(5000)
}
}
fun getAllFilesFlow(): Flow<List<File>> = flow {
while (true) {
emit(getAllFiles())
delay(5000)
}
}

cocos2d, can we call a function in "sequence" on a sprite?

first I am moving the sprite from a to b. when it reaches b, I need to call a function to work on the sprite, i.e fade, change image etc. I am currently doing it with a "sequence".
var seq_action = cc.Sequence.create(move_action, this.check_basket_under());
But it gives me this error -
CCActionInterval.js:507 Uncaught TypeError: Cannot read property '_timesForRepeat' of undefined
at Function.cc.sequence [as create] (CCActionInterval.js:507)
at Class.sprite_create (app.js:110)
at Class.trigger (CCScheduler.js:261)
at Class.update (CCScheduler.js:167)
at Class.update (CCScheduler.js:480)
at Class.drawScene (CCDirector.js:226)
at Class.mainLoop (CCDirector.js:884)
at callback (CCBoot.js:2160)
In Sequence, you can't directly call function. Add callFunc or callBlock
Here is c++ version example:
auto scale = EaseElasticOut::create(ScaleTo::create(3.0f, 1.0f));
auto calb = CallFunc::create( [this] () {
this->check_basket_under( );
});
auto seq = Sequence::create(scale, calb, NULL);
GameOverLabel->runAction(seq);
For more info google CallFunc, CallFuncN usage in Sequence.

How to create a ReplaySubject with RxCpp?

In my c++ project, I need to create Subjects having an initial value, that may be updated. On each subscription/update, subscribers may trigger then data processing... In a previous Angular (RxJS) project, this kind of behavior was handled with ReplaySubject(1).
I'm not able to reproduce this using c++ rxcpp lib.
I've looked up for documentation, snippets, tutorials, but without success.
Expected pseudocode (typescript):
private dataSub: ReplaySubject<Data> = new ReplaySubject<Data>(1);
private init = false;
// public Observable, immediatly share last published value
get currentData$(): Observable<Data> {
if (!this.init) {
return this.initData().pipe(switchMap(
() => this.dataSub.asObservable()
));
}
return this.dataSub.asObservable();
}
I think you are looking for rxcpp::subjects::replay.
Please try this:
auto coordination = rxcpp::observe_on_new_thread();
rxcpp::subjects::replay<int, decltype(coordination)> test(1, coordination);
// to emit data
test.get_observer().on_next(1);
test.get_observer().on_next(2);
test.get_observer().on_next(3);
// to subscribe
test.get_observable().subscribe([](auto && v)
printf("%d\n", v); // this will print '3'
});

Change value of parameter in NSubstitute

I have this method to mock with NSubstitute:
public T VoerStoredProcedureUit<T>(string naam, params SqlParameter[] parameters)
The test method using it sends 2 SqlParameters to this method. VoerStoredProcedureUit is supposed to change the values of these parameters so the tested method can extract that.
I created the following with NSubstitute:
SqlParameter[] param =
{
new SqlParameter("#pat_id", SqlDbType.BigInt) {Direction = ParameterDirection.Output, Value = "Melding"},
new SqlParameter("#Melding", SqlDbType.VarChar, 4096) {Direction = ParameterDirection.Output, Value = 2}
};
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
{
x[1] = param;
return PatientNieuwResultaat.Succes;
});
The setup however rises an exception:
A first chance exception of type 'NSubstitute.Exceptions.ArgumentIsNotOutOrRefException' occurred in NSubstitute.dll
Additional information: Could not set argument 1 (SqlParameter[]) as it is not an out or ref argument.
How do you return a value if the method uses implicitly by reference values?
If I understand your question correctly, you're trying to return the contents of param when VoerStoredProcedureUit<PatientNieuwResultaat> is called.
In ReturnsForAnyArgs, x[1] refers to the second parameter which is an SqlParameter[]. This isn't a ref/out parameter so you can't reassign it in the caller, which is why you get an error. Instead, you need to copy the elements from your template, into the supplied array. Something like this:
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
{
for (int i = 0; i < param.Length; i++)
{
((SqlParameter[])x[1])[i] = param[i];
}
return PatientNieuwResultaat.Succes;
});
You could obviously remove the for loop, since you know how many parameters you need to copy...
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs((x) =>
{
((SqlParameter[])x[1])[0] = param[0];
((SqlParameter[])x[1])[1] = param[1];
return PatientNieuwResultaat.Succes;
});
I found a working solution. Assigning a new variable to the parameters did't work somehow, but changing them does. Also, the second of the method parameter is an array, so it should be treated as such.
productieVerbinding.VoerStoredProcedureUit<PatientNieuwResultaat>(Arg.Any<string>(),
Arg.Any<SqlParameter[]>()).ReturnsForAnyArgs(x =>
{
paramPatId = ((SqlParameter[])x[1])[0];
paramMelding = ((SqlParameter[])x[1])[1];
paramPatId.Value = (long)2;
paramMelding.Value = "Melding";
return PatientNieuwResultaat.Succes;
});

How to wait for a promise to be fulfilled before continuing

How can I wait until a Promise is resolved before executing the next line of code?
e.g.
var option = null;
if(mustHaveOption){
option = store.find("option", 1).then(function(option){ return option })
}
//wait until promise is resolved before returning this value
return option;
rallrall provided the correct answer in his comment: you can't
The solution for me was to redesign my code to return promises and then the receiving function must evaluate the result something along the lines of:
function a(){
var option = null;
return mustHaveOption ? store.find("option", 1) : false;
}
}
function b(){
res = a();
if (!res){
res.then(function(option){
// see option here
});
}
}
Another key solution for me was to use a hash of promises. One creates an array of all the promises that must be resolve before executing the next code:
Em.RSVP.Promise.all(arrayOfPromises).then(function(results){
//code that must be executed only after all of the promises in arrayOfPromises is resolved
});
It tooks me a while to wrap my head around this async way of programming - but once I did things work quite nicely.
With ES6, you can now use the async/await syntax. It makes the code much more readable:
async getSomeOption() {
var option = null;
if (mustHaveOption) {
option = await store.find("option", 1)
}
}
return option;
PS: this code could be simplified, but I'd rather keep it close from the example given above.
You can start to show a loading gif, then you can subscribe to the didLoad event for the record, inside which you can continue your actual processing..
record = App.User.find(1);
//show gif..
record.on("didLoad", function() {
console.log("ren loaded!");
});
//end gif; continue processing..