Suppose I have a cmod function:
PIKEFUN array decodedatarow(int msglen, object portal) { ... }
Which is called as:
class portal { int a; int b; };
portal abc=portal();
decodedatarow(12, abc);
How would I access the svalues of the members a and b from within the cmod function decodedatarow() ?
struct svalue a, b; object_index_no_free(&a, portal, 0, MK_STRING_SVALUE("a")); object_index_no_free(&b, portal, 0, MK_STRING_SVALUE("b"))
And to set them:
object_set_index(portal, 0, MK_STRING_SVALUE("a"), &a); object_set_index(portal, 0, MK_STRING_SVALUE("b"), &b);
Marcus Comstedt (ACROSS) (Hail Ilpalazzo!) @ Pike (-) developers forum wrote:
And to set them:
object_set_index(portal, 0, MK_STRING_SVALUE("a"), &a); object_set_index(portal, 0, MK_STRING_SVALUE("b"), &b);
Thanks. That got me on the right track.
One more question:
When doing the following:
Pike_sp++; object_index_no_free2(Pike_sp-1, portal, 0, MK_STRING_SVALUE("_total"));
What am I supposed to do to cleanup after using the returned svalue?
Pike_sp--; or pop_stack();
?
And, on a related note, what if I do:
Pike_sp++; object_index_no_free2(Pike_sp-1, portal, 0, MK_STRING_SVALUE("_total")); ... some processing ... object_set_index2(portal,0, MK_STRING_SVALUE("_total"), Pike_sp-1);
What do I need at this point, Pike_sp-- or pop_stack() ?
In the above examples the values of _total could have been arrays or ints or strings; I presume the answers are the same regardless of the datatype.
object_index_no_free*() will add a reference for the item on the stack, so you need to free the svalue afterwards, which is conveniently done by pop_stack(). There is no difference between your two snippets; object_index_no_free*() adds a ref, so you need to subtract it when you're done.
Marcus Comstedt (ACROSS) (Hail Ilpalazzo!) @ Pike (-) developers forum wrote:
object_index_no_free*() will add a reference for the item on the stack, so you need to free the svalue afterwards, which is conveniently done by pop_stack(). There is no difference between your two snippets; object_index_no_free*() adds a ref, so you need to subtract it when you're done.
So how do I do an efficient:
class A { array b; };
A c=A(); ... then from with the CMOD:
c->b+=({12});
I would like the += code to destructively expand array b, which would be possible if it had only one reference. But object_index_no_free adds a reference, you say. So how do I solve this?
I use this: push_int(12); f_aggregate(1); Pike_sp++; object_index_no_free2(Pike_sp-1, portal,0, MK_STRING_SVALUE("_datarows")); stack_swap(); f_add(2); object_set_index2(portal,0, MK_STRING_SVALUE("_datarows"), Pike_sp-1); Pike_sp--;
I realise that I need to run pop_stack() at the end instead, but that still leaves me puzzled about the efficient append.
The reference to the old array on the stack is removed by f_add(). So the extra reference you should be worried about is the one in _datarows. Because as long as the variable in the object holds a reference to the old array, it can not be destructively modified. I expect setting _datarows to 0 after the index_no_free2() but before the f_add() should do the trick, but maybe there is a more elegant solution?
Marcus Comstedt (ACROSS) (Hail Ilpalazzo!) @ Pike (-) developers forum wrote:
The reference to the old array on the stack is removed by f_add(). So the extra reference you should be worried about is the one in _datarows. Because as long as the variable in the object holds a reference to the old array, it can not be destructively modified. I expect setting _datarows to 0 after the index_no_free2() but before the f_add() should do the trick, but maybe there is a more elegant solution?
Well, I went with this:
f_aggregate(nrows); Pike_sp++; object_index_no_free2(Pike_sp-1, portal,0, MK_STRING_SVALUE("_datarows")); if(Pike_sp[-1].u.array->size) { push_undefined(); object_set_index2(portal,0, MK_STRING_SVALUE("_datarows"), Pike_sp-1); pop_stack(); stack_swap(); f_add(2); } else pop_stack(); object_set_index2(portal,0, MK_STRING_SVALUE("_datarows"), Pike_sp-1); pop_stack();
Because, as it turns out, in most cases, the array is empty before we start.
You should check that the value actually is an array before accessing .u.array. Otherwise it looks ok.
Well, I went with this:
Pike_sp++; object_index_no_free2(Pike_sp-1, portal,0, MK_STRING_SVALUE("_datarows"));
For error throwing consistency reasons, it's better to swap the above two lines; eg:
| object_index_no_free2(Pike_sp, portal,0, MK_STRING_SVALUE("_datarows")); | Pike_sp++;
Otherwise, the error cleanup code will pop an uninitialized stack value in case object_index_no_free() throws an error.
-- Sincerely, Stephen R. van den Berg.
Hm, if you work on the stack anyway, wouldn't it be easier to push what you want indexed, push_text("something") and call f_index(2)?
Mirar @ Pike developers forum wrote:
Hm, if you work on the stack anyway, wouldn't it be easier to push what you want indexed, push_text("something") and call f_index(2)?
If that can handle an object/class pointer in 'portal', and then dereference it using a pikestring or svalue-string, yes.
It's not immediately clear that this works, since it is not documented anywhere, I learn mostly by grepping for sample code that does/did the same in the Pike repository.
Well, it would do exactly the same thing as would happen in Pike itself.
push_object(obj); push_text("something"); f_index(2);
<->
obj->something;
(or rather obj["something"] iirc. f_arrow() for ->-indexing.)
Mirar @ Pike developers forum wrote:
Well, it would do exactly the same thing as would happen in Pike itself.
push_object(obj); push_text("something"); f_index(2);
I went with something like:
ref_push_object(portal); ref_push_string(MK_STRING("_datarowdesc")); f_arrow(2); datarowdesc=Pike_sp[-1].u.array; pop_stack();
And about type checking, the helper class knows that the types are filled correctly before it's being called. I only need to account for bad user input/database behaviour.
Incidentally, it's these silly things like, when to use push_string or when to use ref_push_string and the same for push_object vs. ref_push_object which take time to figure out.
ref_push_string(MK_STRING("_datarowdesc"));
That's more or less what push_text does. I think. Possibly MK_STRING is better optimized via cmod? push_text seems to recreate the shared pointer every time.
f_arrow(2); datarowdesc=Pike_sp[-1].u.array; pop_stack();
Possibly you either want to increase the reference counter of the array, or use Pike_sp--; instead of pop. (But maybe you do that already, or cmod does it magically for you?)
Incidentally, it's these silly things like, when to use push_string or when to use ref_push_string and the same for push_object vs. ref_push_object which take time to figure out.
Yes. :p
Mirar @ Pike developers forum wrote:
ref_push_string(MK_STRING("_datarowdesc"));
That's more or less what push_text does. I think. Possibly MK_STRING is better optimized via cmod? push_text seems to recreate the shared pointer every time.
MK_STRING does something very clever and rather optimal.
f_arrow(2); datarowdesc=Pike_sp[-1].u.array; pop_stack();
Possibly you either want to increase the reference counter of the array, or use Pike_sp--; instead of pop. (But maybe you do that already, or cmod does it magically for you?)
Good point. No, it doesn't happen, then again, program logic dictates that nobody is messing with that array, the only thing that could mess this up is an unexpected destruction of this object. I'll ponder it some more and see if this safeguard is necessary (and where I need it as well, because I use this construct on three or four items).
Incidentally, it's these silly things like, when to use push_string or when to use ref_push_string and the same for push_object vs. ref_push_object which take time to figure out.
Yes. :p
And the coredumps that follow don't really give enough clues.
Marcus Comstedt (ACROSS) (Hail Ilpalazzo!) @ Pike (-) developers forum wrote:
object_index_no_free*() will add a reference for the item on the stack, so you need to free the svalue afterwards, which is
Incidentally, what does the "no_free" in object_index_no_free() refer to then? That the target svalue is not freed before overwriting? That the source svalue is not freed, but normally it would have been? And if the latter, then how is that supposed to work, since it wouldn't make much sense to extract the value from the class and then automatically delete it, or?
Incidentally, what does the "no_free" in object_index_no_free() refer to then? That the target svalue is not freed before overwriting?
Exactly. So it is the correct version to use when the svalue you are overwriting is not initialized (uninitialized C variable, new stack entry etc).
Stephen R. van den Berg wrote:
PIKEFUN array decodedatarow(int msglen, object portal) {
class portal { int a; int b; };
After digging through the Pike sources, the best I can come up with is something like:
safe_apply(portal,"a",0);
But that doesn't seem right, and it also doesn't tell me how to handle things like: portal->a += 7; from within the cmod function.
I get the impression that in none of the existing C(MOD)-modules this is attempted (I see lots of calls to methods of other classes, but no references to variables), so I'm missing an example here.
pike-devel@lists.lysator.liu.se