Last argument 'pop' (like shift)
Foo(){
shift;
pop; # does not work grr
}
Foo removeme abc removeme
Foo() {
shift
set -- "${@:1:$#-1}" # Pop
echo "$@"
}
Foo removeme abc removeme # abc
Here's a posix way, though it's very hacky
Foo() {
shift
# Pop
local index=0
local arguments=""
while [ $index -lt $(($#-1)) ]; do
index=$((index+1))
arguments="$arguments \"\$$index\""
done
eval "set -- $arguments"
echo "$@"
}
Foo removeme abc removeme # abc
This could indeed be implemented as a pop keyword in powscript. I will do it tomorrow! I need to get back to this.
fcard! Interesting, you're using 'set' to overwrite the positioned variables?
Hello! It's been a while.
And yes, set -- x y z sets $1 to x, $2 to y, and $3 to z, with the -- preventing any of the arguments from being interpreted as options, otherwise if an argument was "-e" or something it would fail. That's the only way I could think of to implement this pop functionality, unfortunately there isn't a way to set a specific positional argument that I know of.
I am going to give it a try implementing this in a moment. Thankfully it seems like I still remember most of the details about this codebase!
I've been trying to get the Posix version to be faster, and this is what I've come up:
PopSet() {
local N=$(($1 - ${2:-0}))
local index=0 i1 i2 i3 i4 i5 i6 i7 i8 i9
local arguments=""
case $N in
1) _POP_ARGS='';;
2) _POP_ARGS='"$1"' ;;
3) _POP_ARGS='"$1" "$2"' ;;
4) _POP_ARGS='"$1" "$2" "$3"' ;;
5) _POP_ARGS='"$1" "$2" "$3" "$4"' ;;
6) _POP_ARGS='"$1" "$2" "$3" "$4" "$5"' ;;
7) _POP_ARGS='"$1" "$2" "$3" "$4" "$5" "$6"' ;;
8) _POP_ARGS='"$1" "$2" "$3" "$4" "$5" "$6" "$7"' ;;
9) _POP_ARGS='"$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8"' ;;
*)
while [ $index -lt $((N-9)) ]; do
i1=$((index+1))
i2=$((index+2))
i3=$((index+3))
i4=$((index+4))
i5=$((index+5))
i6=$((index+6))
i7=$((index+7))
i8=$((index+8))
i9=$((index+9))
arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\" \"\$$i4\" \"\$$i5\" \"\$$i6\" \"\$$i7\" \"\$$i8\" \"\$$i9\""
index=$i9
done
case $((N%9)) in
2) arguments="$arguments \"\$$i1\"" ;;
3) arguments="$arguments \"\$$i1\" \"\$$i2\"" ;;
4) arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\"" ;;
5) arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\" \"\$$i4\"" ;;
6) arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\" \"\$$i4\" \"\$$i5\"" ;;
7) arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\" \"\$$i4\" \"\$$i5\" \"\$$i6\"" ;;
8) arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\" \"\$$i4\" \"\$$i5\" \"\$$i6\" \"\$$i7\"" ;;
0) arguments="$arguments \"\$$i1\" \"\$$i2\" \"\$$i3\" \"\$$i4\" \"\$$i5\" \"\$$i6\" \"\$$i7\" \"\$$i8\"" ;;
esac
_POP_ARGS="$arguments"
;;
esac
}
Foo() {
PopSet $#
eval "set -- $_POP_ARGS"
echo "$@"
}
Foo a b c # a b
This is about as fast on dash as bash's pop is on bash, which isn't too shabby. Neither of them scale as well as shift when being called multiple times in a function though, so putting it in a loop could slow down scripts. That said, unsetting the last element of an array is O(1) and it's not too hard to do right now:
Foo(@args)
local length=${args[@]:length}
unset args[$length-1]
echo $args[@]
Foo a b c # a b
In addition to the positional arguments pop we could add an array:pop and an array:shift as well that could be used like this:
Foo(@args)
array:shift args
array:pop args
echo "$@"
Foo a b c # b
They could be implemented in the lib/std.pow file simply as
array:shift(A)
expand
~A=(${~A[@]:slice 1})
array:pop(A)
expand
unset ~A[${~A[@]:length}-1]
(The issue with using arrays of course is that while pop becomes O(1), shift becomes O(n). weh!)
interesting!
I can see you were in a creative mood :)
The string-composition using case seems to indicate that for-loops were too expensive?
I really like the usage of array:shift and array:pop as they are also useful outside of the pop/push scenario.
The initial case statement is simply because I assume that most function calls won't have >9 arguments, so we simply go to the result, and in the case of a large amount of arguments, a case statement is such a light thing it won't matter in the end.
For the rest, the main issue is that string concatenation is expensive, specially if you have many small operations, so I figured the best way to cut out the expense was to concatenate the indexes in batches; I picked 9 as a good not too large not too small number, and it was enough to match the bash version in speed in most of my benchmarks. Though, only in dash, in bash it's still 2-4x slower than just using the sub-array method, so we should still use it there.
Sorry for the break, I was doing research on this pop predicament, which I've compiled here: https://github.com/fcard/pop.sh I am also busy with a game project, so I will be multitasking between this and that, but I still want to come back to this proper, nyeh Expect a pull request a few hours from now!
Absolutely no problem, no need to stress, otherwise it's not fun to work on :)
On Thu, Sep 17, 2020 at 9:11 PM fcard [email protected] wrote:
Sorry for the break, I was doing research on this pop predicament, which I've compiled here: https://github.com/fcard/pop.sh I am also busy with a game project, so I will be multitasking between this and that, but I still want to come back to this proper, nyeh Expect a pull request a few hours from now!
β You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/coderofsalvation/powscript/issues/67#issuecomment-694441350, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABL6ZGD722MJKLNAU2U7PLSGJNNXANCNFSM4NWMXNBQ .
--
LΓ©on
/COMPANY
/WEBSITE
/MOBILE
/LOCATION
/COMPANYNR.
/TAGS
van Kammen
2WA Labs & Consultancy
2wa.isvery.ninja/hello
+31 20 3699836
Holland, EU, Galaxy 12B
08124656
Creative Technologist, New Media
consultancy, Tech concept design,
driven by open source &
lots of coffee.
https://www.linkedin.com/in/leonvankammen https://github.com/coderofsalvation