Lua:
a = {
b = "c",
d = {
e = "f",
g = "h"
}
}
setmetatable(a.d, {__ismt = true})
cfun(a) --call C function to iterate over table a
C:
int cfun(lua_State *L)
{
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
// iterate over table
lua_pop(L, 1);
}
}
How do you know if there is a metatable when the host client iterates over the table? And then how do you get the metatable?
The table is in a form of a tree, and you need to traverse the tree in iterative mode. Lua already has a stack implementation, so this makes the job easier.
On entrance, the stack has the table at top, you will push a nil element since lua_next() will consume one element from the stack before checking the table. So the stack will look like table -> nil.
Next, we are calling lua_next() which will consume one element from the stack and will add two new key-value pair from the table. The stack will look like table -> key -> value. If there is no next element, the return value of the call is 0.
If the return value is 1, and the value on stack is a nested table, you will push nil on the stack, so now the stack will look like table -> key -> table -> nil. Now you are almost like on the begining, so with the loop, you will start traversing the nested table.
if the return value is 1, and if the value is not table, to your stuff with the value
if the return value is 0, we can check if this was a meta table. After the check, you will pop the value and check if the stack is table -> key or any -> key. If the second element on the stack is not a table, you have finished the traversing and you will break the loop.
Here is the C code that implements the algorithm. I have left the printf in order to help debugging. The printf() should be removed.
static int cfun(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushnil(L); // Add extra space for the first lua_next to pop
int loop=1;
do {
if ( lua_next(L,-2) != 0 ) {
if (lua_istable(L,-1)) {
printf("Table [%s] \n", lua_tostring(L, -2));
lua_pushnil(L); // Start iterating this sub-table
} else {
// The Key and Value are on the stack. We can get their type
printf("(%s - %s)\n",
lua_tostring(L, -2),
lua_typename(L, lua_type(L, -1)));
lua_pop(L,1);
}
} else {
printf("table finished, still on stack (%s -> %s -> %s)\n",
lua_typename(L, lua_type(L, -3)),
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
if (lua_getmetatable(L,-1)) {
// The table has metatable. Now the metatable is on stack
printf("Metatable detected\n");
lua_pop(L,1); // remove the metatable from stack
}
lua_pop(L,1); // Pop the current table from stack
if (!lua_istable(L, -2)) {
loop = 0; // No more tables on stack, breaking the loop
}
}
} while (loop);
lua_pop(L,1); // Clear the last element
lua_pushnumber(L,0); // Return 0
return 1;
}
Related
Basically I'm trying to implement a table with help of an array. The array functionality is already given and should not be altered. What I'm having trouble configuring is my table_remove function. Keep in mind that I'm not striving for the most effective way to do this.
What I tried to do is loop through the entire table to find if there is a key that matches.
If the key is found, save the position.
If not exit.
So after the position is found I set it to free the key & value on that position in hope that it will 'remove' the key & value pair from that position. However, my given test program returns "Removing the last element from a table does not result in an empty table.". If I add in the end "array_setVal(array, NULL, index) then the entire program crashes (Probably because it tries to write on that null position further on in the test).
So now I'm wondering if I'm approaching this issue the wrong way and have to do further operations to actually remove the value from the position without sort of messing up the position itself so next time I use table_insert, the position will be empty and another key & value pair will be inserted in that spot.
int saveRemovedIndex = -1;
/* Check if the key already exists */
for(int indexCounter = 0; indexCounter <= MAXINDEX; indexCounter++){
i = array_inspectValue(t->values, indexCounter);
if (t->cf(i->key,key)==0) {
saveRemovedIndex = indexCounter;
break;
}
}
/* Checks if the key actually exists in the table.
* If it exists, remove it. Else quit.*/
if (saveRemovedIndex != -1) {
i = array_inspectValue(t->values, saveRemovedIndex);
if(t->keyFree!=NULL) {
t->keyFree(i->key);
}
if(t->valueFree!=NULL) {
t->valueFree(i->value);
}
} else {
return;
}
I created a more or less complex table in C. Now I want to create a reference on a lower level of the tree. Is this possible?
Idea:
ELEM000 +--> ELEM010
+--> ELEM020 +--> ELEM120
| +--> **ELEM121**
| +--> ELEM122
+--> ELEM030 +--> ELEM130
| +--> ELEM131
| +--> ELEM132
+--> **ELEM121**
The ELEM121 should also be visible one level above, i.e. be a reference
I added an example of what I wanted to to..
void PushL(lua_State *L, const char * str) {
char s[255];
strcpy(s, "ELEM"); strcat(s, str); lua_pushstring(L, s); // key
strcpy(s, "Value"); strcat(s, str); lua_pushstring(L, s); // value
lua_settable(L, -3);
}
void MakeTable( lua_State *L )
{
lua_pushstring(L, "TBL0"); // name of sub-table
lua_createtable(L, 0, 0);
lua_checkstack(L, 3);
{
PushL(L, "000");
lua_pushstring(L, "TBL1");
lua_createtable(L, 0, 0);
lua_checkstack(L, 3);
{
PushL(L, "010");
PushL(L, "020");
lua_pushstring(L, "TBL2");
lua_createtable(L, 0, 0);
lua_checkstack(L, 3);
{
PushL(L, "120");
PushL(L, "121");
PushL(L, "122");
lua_settable(L, -3);
}
PushL(L, "030");
lua_pushstring(L, "TBL3");
lua_createtable(L, 0, 0);
lua_checkstack(L, 3);
{
PushL(L, "130");
PushL(L, "131");
PushL(L, "132");
lua_settable(L, -3);
}
lua_settable(L, -3);
}
lua_pushstring(L, "ELEM121");
lua_pushstring(L, "SHOULD BE A REFERENCE TO ELEM121");
lua_settable(L, -3);
}
lua_setglobal(L,"____myTable");
}
Bottom line: In Lua, field variables cannot be referenced but there are ways of doing what you want.
Here is a comparison between C data structures and Lua data structures.
In C, you either:
have a copy of the value in two places
You can create copies in Lua, too.
or, have a pointer in one place that points to the other place.
In C, that means you'd have to access them differently, one with a pointer deference, the other without.
In Lua, you could have a function in one place that returns the value in the other place. That means you'd have to access them differently, one with a function call, the other without.
The following is equivalent to a read-only pointer:
local ELEM000 = {
ELEM010 = "ELEM010 value",
ELEM020 = {
ELEM120 = "ELEM120 value",
ELEM121 = "ELEM121 value",
ELEM122 = "ELEM122 value" },
ELEM030 = {
ELEM130 = "ELEM130 value",
ELEM131 = "ELEM131 value",
ELEM132 = "ELEM132 value" },
ELEM121 = function(self) return self.ELEM020.ELEM121 end }
print(ELEM000.ELEM020.ELEM121)
print(ELEM000:ELEM121())
ELEM000.ELEM020.ELEM121 = ELEM000.ELEM020.ELEM121 .. " updated"
print(ELEM000.ELEM020.ELEM121)
print(ELEM000:ELEM121())
If you need a writable pointer then another approach would be needed.
Update
A simple way for a writable pointer is to add an optional value parameter. This is commonly used in JavaScript APIs but JavaScript has the advantage of the undefined data type. In Lua, we'll have to use nil, which means that you can't write nil as a value.
ELEM121 = function(self, value)
if (value ~= nil) then self.ELEM020.ELEM121 = value end
return self.ELEM020.ELEM121
end
For true read-write field access, use the __index and __newindex metatmethods. This requires that the field actually not have a key in the table. The metamethods are invoked when indexing a non-existing field for reading (__index) or for writing (__newindex).
local ELEM000 = {
ELEM010 = "ELEM010 value",
ELEM020 = {
ELEM120 = "ELEM120 value",
ELEM121 = "ELEM121 value", -- captured as the initial value
ELEM122 = "ELEM122 value"},
ELEM030 = {
ELEM130 = "ELEM130 value",
ELEM131 = "ELEM131 value",
ELEM132 = "ELEM132 value" },
ELEM121 = nil -- ignored
}
setmetatable(ELEM000, {
__index = function(base, key)
if (key=="ELEM121") then return base.ELEM020.ELEM121
else return nil end end,
__newindex = function (base, key, value)
if (key=="ELEM121") then base.ELEM020.ELEM121 = value
else rawset(base, key, value) end end })
setmetatable(ELEM000.ELEM020, {
ELEM121 = ELEM000.ELEM020.ELEM121, --[[ backing storage for field,
initialized to existing value]]
__index = function(base, key)
if (key=="ELEM121") then return getmetatable(base).ELEM121
else return nil end end,
__newindex = function (base, key, value)
if (key=="ELEM121") then getmetatable(base).ELEM121 = value
else rawset(base, key, value) end end })
-- make sure metamethods will be invoked on these fields
rawset(ELEM000, "ELEM121", nil)
rawset(ELEM000.ELEM020, "ELEM121", nil)
Usage:
print(ELEM000.ELEM020.ELEM121)
print(ELEM000.ELEM121)
ELEM000.ELEM020.ELEM121 = ELEM000.ELEM020.ELEM121 .. " updated"
print(ELEM000.ELEM020.ELEM121)
print(ELEM000.ELEM121)
ELEM000.ELEM121 = ELEM000.ELEM121 .. " again"
print(ELEM000.ELEM020.ELEM121)
print(ELEM000.ELEM121)
There various places to store the backing field and different styles of coding the metamethods. This code is perhaps too concise. And, I leave it to you to code it in Lua C API, if you wish.
I'm trying to create a method which will add a char* to a LinkedList, ensuring that the linkedList is always sorted alphabetically. I have been given code to define a LinkedItem struct:
// Define our list item as 'struct ListItem', and also
// typedef it under the same name.
typedef struct ListItem {
char *s;
struct ListItem *p_next;
} ListItem;
I have also been given a method to add an item to the beginning of a list:
// Adds a new item to the beginning of a list, returning the new
// item (ie the head of the new list *)
ListItem* add_item(ListItem *p_head, char *s) {
// Allocate some memory for the size of our structure.
ListItem *p_new_item = malloc(sizeof(ListItem));
p_new_item->p_next = p_head; // We are the new tail.
p_new_item->s = s; // Set data pointer.
return p_new_item;
}
Now here's my code, I'll explain more after:
ListItem* addSortedItem(ListItem *p_head, char *s){
if(p_head==NULL)//if the list is empty, we add to the beginning
return add_item(p_head,s);
ListItem* p_new_item = malloc(sizeof(ListItem));
ListItem *p_current_item = p_head; //makes a pointer to the head of the list
while (p_current_item) { // Loop while the current pointer is not NULL
printf("entering while loop with current=%s\n",p_current_item->s);
// now we want to look at the value contained and compare it to the value input
if(aThenB(s,p_current_item->s)!=TRUE){
// if A goes after B, we want to go on to look at the next element
p_current_item=p_current_item->p_next;
} else if (aThenB(s,p_current_item->s)==TRUE) {printf("entered elseif\n");
p_head=add_item(p_current_item,s);
return p_head;
} else {printf("WHY DID WE EVER REACH THE ELSE!?"); return p_head;}
}
}
Now, aThenB(StringA,StringB) returns TRUE if the correct sorted order of A and B is A, then B, and false otherwise- equality is also an option, I simply haven't gotten this to work well enough to allow that :-)
What is happening with my test data (which is "sheep i", with i from 0-10) is that either I am only returning one element back, or i am randomly skipping elements, depending on the order input. I can include more code but it's a bit messy.
I think my problem is stemming from not fully understanding the pointers and how they work- I want to ensure that p_head is always pointing to the head, whilst p_current is roving through the list. But I'm also getting seg faults when p_current reaches the last element, so I'm not sure where I'm going wrong.
Thank you for any help on how to get my code to return properly :-)
Edit: addSortedItem() is called in the following block in the main method:
// The empty list is represented by a pointer to NULL.
ListItem *p_head = NULL;
ListItem *p_head2=NULL;
// Now add some items onto the beginning of the list.
int i;
for (i=0; i<NO_ITEMS; i++) {
// Allocate some memory for our string, and use snprintf to
// create a formatted string (see GNU API docs) much like printf
// but instead writing to memory rather than the screen.
char* s = malloc(MAX_DATA_CHARS);
snprintf(s, (size_t) MAX_DATA_CHARS, "sheep %d", i);
p_head = addSortedItem(p_head, s);
}
you have an error in the add of a new element in the middle or in the end of the linked list.
in your addStoredItem function you make a pointer from your newItem to the currentItem but you do not take account to have a link from previous element to the newItem
initial linked list befor calling addStoredItem
item1-->item2-->item4-->item5
Linked list afetr calling addStoredItem in order to add item3
item1-->item2-->item4-->item5
^
|
item3
so as you can see you have added the new item at the head of the sub linked list starting from item4 but you do not make link from item2 to item3
so that we have to keep a pointer to the previous item in order to complete the link.
the add_item() function allow to add item in the head
The same thing if you try to add item at the end of the linked list
item1-->item2-->item4-->item5 NULL
^
|
item6
the item6 has added as separate head and there is no link from item5 (previous) to item6 (new)
so your addStoredItem() function could be fixed like this
ListItem* addSortedItem(ListItem *p_head, char *s){
if(p_head==NULL)//if the list is empty, we add to the beginning
return add_item(p_head,s);
struct ListItem* p_new_item = malloc(sizeof(ListItem));
ListItem *p_current_item = p_head; //makes a pointer to the head of the list
ListItem *p_prev_item = NULL; //FIXED
while (p_current_item) { // Loop while the current pointer is not NULL
printf("entering while loop with current=%s\n",p_current_item->s);
// now we want to look at the value contained and compare it to the value input
if(aThenB(s,p_current_item->s)!=TRUE){
// if A goes after B, we want to go on to look at the next element
p_prev_item = p_current_item; //FIXED
p_current_item=p_current_item->p_next;
} else if (aThenB(s,p_current_item->s)==TRUE) {printf("entered elseif\n");
break;
} else {printf("WHY DID WE EVER REACH THE ELSE!?"); return p_head;}
}
if (p_prev_item!=NULL) //FIXED
p_prev_item->p_next=add_item(p_current_item,s); //FIXED
else //FIXED
p_head=add_item(p_current_item,s);//FIXED
return p_head; //FIXED
}
the fixed lines are indicated with //FIXED
At first, your p_head is NULL, so when you enter your addSortedItem function you create the list and add the first string. That's alright.
But then, upon adding the second item (which in your case is "sheep 1"), you enter your while (p_current_item) loop. The call to aThenB returns FALSE and you go to your next element which is.. NULL! Indeed, at this time, p_head looks like this:
p_head {
s = "sheep 0",
p_next = NULL
}
Your while condition is not true and you exit your function, nothing was added.
You could add a condition in your first if like:
if (p_current_item->next == NULL)
p_current_item->next = addSortedItem(NULL, s);
else
p_current_item = p_current_item->next;
Also, saying that p_head=add_item(p_current_item,s); is wrong. Suppose your list is something like:
"sheep 1" -> "sheep 2" -> "sheep 4" -> "sheep 5"
If you add "sheep 3", you will get this:
"sheep 1" -> "sheep 2" -> "sheep 3" -> "sheep 4" -> "sheep 5"
^
|
p_head
You won't be able to add "sheep 0" anymore. Don't return the return value of addSortedItem as the new p_head
Support stuff:
#define FALSE 0
#define TRUE 1
#define aThenB(a,b) (strcmp(a,b) <=0 ? TRUE : FALSE)
All the special cases can be avoided by modifying the function's signature to
accept a pointer to pointer.
void addSortedItem(ListItem **pp_head, char *s){
ListItem *p_new_item ;
for ( ;*pp_head; pp_head = &(*pp_head)->p_next) {
if (aThenB(s,(*pp_head)->s)==FALSE) break;
}
p_new_item = malloc(sizeof *p_new_item);
p_new_item->s = s;
p_new_item->p_next = *pp_head;
*pp_head = p_new_item;
}
The caller should do:
ListItem *root = NULL;
addSortedItem( &root, "sheep#0");
Hello I am really stumped with this seemingly simple task.
I can access the properties of a table passed to a function in C, but cannot access the members of any subtable i create in it.
Basically I want to simply be able to extract the strings from the properties table so i can create say a "wheel" according to the users expectations.
Here is what I have so far (tried so much my brain is fried)
Lua Side:
--Function
createSomething( "wheel", { canInflate = true, properties = { "large", "full" } } )
C Side:
//I can retrieve any value easily within that table, but cannot seem to extract the table
//Within it named "properties", i can access the table, but cannot extract the strings inside
if( lua_istable(L, 2) ) {
lua_getfield(L, 2, "canInflate"); // Let's extract the value for the key 'someKey'. Pushes the value on the top of the stack
static int canInflate = lua_toboolean(L, -1); // get the value of bool now at the top of stack (index: -1)
//printf("can inflate is %d\n", canInflate);
//lua_pop(L, 1); // pop the value now that we are done with it
}
//try to get the properties table
if ( lua_istable(L, 2) ) {
lua_getfield(L, 2, "properties");
const char *str = lua_tostring(L, -1);
printf( "properties 1 = %s\n", str); // NULL
lua_pop(L, 2);
}
Any help on this would be greatly appreciated
The problem you're having is with how you specify tables in Lua: the following 3 statements have exactly the same result:
t = { 'full','large'}
t = { [1] = 'full', [2] = 'large'}
t={};t[1]='full';t[2]='large'
What you want is to use the strings as keys instead of values (as is done in your code and the above samples):
t={full=true,large=true}
-- or
t={}; t.full=true; t.large=true
If you use the strings as keys your C code should work.
I have a stack which contains some integer data. I want to find out the min value from Stack in O(1) time. Any idea?
PS: There is no ordering (increasing/decreasing) of data in Stack.
Thanks,
Naveen
Use two stacks. One is the data, one is the minimums. When you push onto the data stack, push the new minimum onto the minimums stack (the new minimum is the min of the item you're pushing and whatever is currently on the top of the minimums stack), and when you pop, pop off of both stacks (so that the two stacks always have the same number of elements). To find the minimum element, just look at the top of the minimums stack.
Pushing, popping and finding the min value are O(1).
O(n) is the best you're gonna do - you'd have to check each one of the values and compare them to the aggregator minimum, otherwise how would you know you got the lowest?
If you want, you can store the minimum as the values are added, making the pushes more expensive for the benefit of an O(1) read (of the pre-calculated minimum), but that's it.
A stack by definition is push/pop (LIFO) data structure. You can't using a single stack!
I am not sure why you expect to do this in constant time for arbitrary length. The best you will be able to do is O(n)
You'll probably want some kind of priority heap if you want to always pop the least element. If you want to pop what was last pushed, but be able to know the order of the elements remaining in the stack, some kind of search tree e.g. red-black will support deletion of an element from an arbitrary position (your stack would have a pointer to the tree node so when you pop you can find it).
If you only need to know the minimum (or max) remaining in the stack then ESRogs' is optimal.
Here is the Python implementation of ESRogs algorithm using lists as stacks:
class ConstantStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self,item):
self.stack.append(item)
if len(self.min_stack) == 0:
self.min_stack.append(item)
return
# Get the smaller item between the pushed item and the top of the stack
smallest = min(item,self.min_stack[-1])
self.min_stack.append(smallest)
def pop(self):
self.min_stack.pop()
return self.stack.pop()
def min(self):
# NOTE: min_stack[-1] is equivalent to peek()
return self.min_stack[-1]
Here is an example of its usage:
>>> s = ConstantStack()
>>> s.push(3)
>>> s.push(7)
>>> s.push(6)
>>> s.push(1)
>>> s.min()
1
>>> s.pop()
1
>>> # Now that 1 is gone, 3 is the next smallest
>>> s.min()
3
>>> s.pop()
6
>>> # 6 was popped but 3 still remains the smallest
>>> s.min()
3
>>> s.pop()
7
>>> s.min()
3
>>> s.pop()
3
#define STACKSIZE 50
typedef struct stack
{
int item[STACKSIZE];
int top;
}MULSTACKEX;
void InitStack(MULSTACKEX &st)
{
st.item[STACKSIZE] = 0;
st.top = -1;
}
void Push(MULSTACKEX &st1, MULSTACKEX &st2, int elem)
{
if(st1.top == -1)
{
st1.top++;
st1.item[st1.top] = elem;
st2.top++;
st2.item[st2.top] = elem;
}
else
{
st1.top++;
st1.item[st1.top] = elem;
if(elem < st2.item[st2.top])
{
st2.top++;
st2.item[st2.top] = elem;
}
}
}
void Display(MULSTACKEX &st1, MULSTACKEX &st2)
{
cout<<"stack1 elements: "<<endl;
for(int i = 0; i <= st1.top; i++)
{
cout<<st1.item[i]<<"->";
}
cout<<endl;
cout<<"stack2 elements: "<<endl;
for(int i = 0; i <= st2.top; i++)
{
cout<<st2.item[i]<<"->";
}
}
int Pop(MULSTACKEX &st1, MULSTACKEX &st2)
{
int elem = 0;
if(st1.item[st1.top] == st2.item[st2.top])
{
elem = st2.item[st2.top];
st2.top--;
elem = st1.item[st1.top];
st1.top--;
}
else
{
elem = st1.item[st1.top];
st1.top--;
}
return elem;
}
int FindMin(MULSTACKEX &st2)
{
int elem = st2.item[st2.top];
return elem;
}
int _tmain(int argc, _TCHAR* argv[])
{
MULSTACKEX stack1, stack2;
InitStack(stack1);
InitStack(stack2);
Push(stack1,stack2,13);
Push(stack1,stack2,17);
Push(stack1,stack2,5);
Display(stack1,stack2);
int min_elem1 = FindMin(stack2);
cout<<"Min element in the list is: "<<min_elem1<<endl<<endl;
int deletedelem2 = Pop(stack1,stack2);
cout<<"Pop element from the stack:"<< deletedelem2 <<endl<<endl;
Display(stack1,stack2);
cout<<endl<<endl;
Push(stack1,stack2,19);
Push(stack1,stack2,8);
Display(stack1,stack2);
cout<<endl<<endl;
int deletedelem1 = Pop(stack1,stack2);
cout<<"Pop element from the stack:"<< deletedelem1 <<endl<<endl;
Display(stack1,stack2);
int min_elem2 = FindMin(stack2);
cout<<"Min element in the list is: "<<min_elem2<<endl<<endl;
return 0;
}
Instead of pushing 1 value, we push a pair of numbers. first element will be element that you want to push, second element would be minimum element of the stack and we should keep track of the minimum element. (element,minOfStack)
let say you have an empty array. when first you push data to the stack,firs element is also minumum value.
data=[(1,1)]
then you add value 2. you check the minimim value of the stack which is 1, 1<2, so you push (2,1) to the array
data=[(1,1),(2,1)]
Here is the python implementation
class StackTrackingMin:
def __init__(self):
self._data=[]
def push(self,x:int)->None:
currentMin=self.getMin()
if currentMin==None or currentMin>x:
currentMin=x
self._data.append((x,currentMin))
def pop(self)->None:
self._data.pop() # pop does not return anything
def top(self)->int:
return self._date[-1] if self._data else None
def getMin(self)->int:
return self._data[-1][1] if self._data else None