Is there anything like pointers in Lua? - pointers

I'm new to Lua and I want to create a table [doh] which would store values like:
parent.child[1].value = "whaterver"
parent.child[2].value = "blah"
however, most often there's only one child, so it would be easier to access the value like this:
parent.child.value
To make things simpler, I would like to store my values, in a way, that
parent.child[1].value == parent.child.value
But to do this I would have to store this value twice in the memory.
Is there any way I could do it, so that:
parent.child.value points to parent.child[1].value
without storing the value twice in the memory?
Additional question is, how to check how much memory does a table take?

but the value will be stored as string, so it's a string that needs to
be referenced in both places, not table.
First, all types (except booleans, numbers and light userdata) are references - if t is a table and you do t2 = t, then both t and t2 are references to the same table in memory.
Second thing - string are interned in Lua. That means that all equal strings, like "abc" and the result of "ab".."c" are actually a single string. Lua also stores only references to strings. So you should not worry about memory - there is only a single instance of the string at a time.
You can safely do parent.child.value = parent.child[1].value, you will only use a memory for one slot in a table (a few bytes), no string will be copied, only referenced.

Lua tables (often used as objects) are not copied, but referenced.
(internally, a pointer is used to them)

This is a nice application for using metatables:
parent={
child={
{value="whatever"},
{value="blah"}
}
}
setmetatable(parent.child,{__index=parent.child[1]})
If an index is not found in the child table (like 'value'), it gets looked up in the table that's the value of __index of the metatable (the first element of child in this case).
Now there is a problem with the above code which we can see as folows:
print(parent.child.value) -- prints whatever
parent.child[1]=nil --remove first child
print(parent.child.value) -- still prints whatever!
This is because the metatable keeps a reference to the first child table, preventing it from being reaped. The workaround for this kind of stuff is A) making the metatable a weak table, or B) make the __index field a function, instead of referencing it to a table.
-- A)
setmetatable(parent.child, setmetatable(
{__index=parent.child[1]} -- metatable for the child table
{__mode='v'}-- metatable for the metatable, making it have weak keys
)
)
parent.child[1]=nil
print(parent.child.value) --returns nil
parent.child[1]={value='foo'}
print(parent.child.value) -- prints nil, the metatable references to a non-existant table.
-- hence solution B)
setmetatable(parent.child, {__index=function(t,k) return parent.child[1][k]})
print(parent.child.value) -- 'whatever'
parent.child[1]=nil
print(parent.child.value) -- nil
parent.child[1]={value='foobar'
print(parent.child.value) -- foobar, now it will always refer to the table at child[1], even when it changes.
If you're really interested to read up on metatables, try reading Programming in Lua, chapter 13 and chapter 17 (weak tables). Lua-Users wiki on MetaMethods might also be interesting.

With C arrays, parent.child and parent.child[0] are equivalent because of pointer arithmetic. You really shouldn't try to emulate one of the most error-prone, confusing and redundant features of C just because you like the style.

Related

How to insert an element into the middle of an array (json) in SQLite?

I found a method json_insert in the json section of the SQLite document. But it seems to be not working in the way that I expected.
e.g. select json_insert('[3,2,1]', '$[3]', 4) as result;
The result column returns '[3,2,1,4]', which is correct.
But for select json_insert('[3,2,1]', '$[1]', 4) as result;
I am expecting something like '[3,2,4,1]' to be returned, instead of '[3,2,1]'.
Am I missing something ? I don't see there is an alternative method to json_insert.
P.S. I am playing it on https://sqlime.org/#demo.db, the SQLite version is 3.37.2.
The documentation states that json_insert() will not overwrite values ("Overwrite if already exists? - No"). That means you can't insert elements in the middle of the array.
My interpretation: The function is primarily meant to insert keys into an object, where this kind of behavior makes more sense - not changing the length of an array is a sacrifice for consistency.
You could shoehorn it into SQLite by turning the JSON array into a table, appending your element, sorting the result, and turning it all back into a JSON array:
select json_group_array(x.value) from (
select key, value from json_each('[3,2,1]')
union
select 1.5, 4 -- 1.5 = after 1, before 2
order by 1
) x
This will produce '[3,2,4,1]'.
But you can probably see that this won't scale, and even if there was a built-in function that did this for you, it wouldn't scale, either. String manipulation is slow. It might work well enough for one-offs, or when done infrequently.
In the long run, I would recommend properly normalizing your database structure instead of storing "non-blob" data in JSON blobs. Manipulating normalized data is much easier than manipulating JSON, not to mention faster by probably orders of magnitude.

Does a "for XXX use" clause make any sense for a null record?

I have been tasked with added representation (rep) clauses for all our record types which will be sent in messages to another processor. It's a different CPU manufacturer, compiler & programming language, so there is a danger of misalignment/misinterpretation.
Obviously, type XXX is record requires a for XXX use with the appropriate byte & bit data for each field.
What about type null_record is null record; ?
for null_record use
null;
end record;
does not compile and doesn't really seem to make sense.
The boss is pushing for 100% rep clause, with 'size, 'alignment 'Object_size, Value_size and pragma pack, but surely that makes no sense for a null record?
It would make sense if a record representation clause forced a component clause for all components. In that case the compiler would detect any changes to the record definition, and thus force you to take a look at the representation clause as well. Of course, that is not the case, so you're right, it doesn't make much sense.
However, if your boss really insists, the correct syntax is:
for null_record use
record
end record;

Delete a key-value pair in BerkeleyDB

Is there any way to delete key-value pair where the key start with sub-string1 and ends with sub-string2 in BerkeleyDB without iterating through all the keys in the DB?
For ex:
$sub1 = "B015";
$sub2 = "5646";
I want to delete
$key = "B015HGUJJ75646"
Note: It is guaranteed that there will be only one key for the combination of $sub1 and $sub2.
This can be done by taking an iterator of the DB and checking every key for the condition, but that will be very in-efficient for large DBs. Is there any way to do it without iterating through the complete DB?
If you're using a RECNO database, you're probably out of luck. But, if you can use a BTREE, you have a couple of options.
First, and probably easiest is to iterate over only the portion of the database that makes sense. Assuming you're using the default key comparison function, you can use DB_SET_RANGE to position the starting cursor (iterator) at the start of your partial key string. In your example, this might be "B0150000000000". You then scan forwards with DB_NEXT, looking at each key in turn. When either you find the key you're looking for, or if the key you find doesn't start with "B015", you're done.
Another technique that could be applicable to your situation is to redefine the key comparison function. If, as you state, there is only one combination of $sub1 and $sub2, then perhaps you only need to compare those sections of the keys to guarantee uniqueness? Here's an example of a full string comparison (I'm assuming you're using perl, just from the syntax you supplied above) from https://www2.informatik.hu-berlin.de/Themen/manuals/perl/DB_File.html :
sub Compare
{
my ($key1, $key2) = #_ ;
"\L$key1" cmp "\L$key2" ;
}
$DB_BTREE->{compare} = 'Compare' ;
So, if you can rig things such that you're only comparing the starting and ending four characters, you should be able to drop the database iterator directly onto the key you're interested in.

Dealing with PL/SQL Collections

I have following declaration for collection
TYPE T_TABLE1 IS TABLE OF TABLE_1%ROWTYPE INDEX BY BINARY_INTEGER;
tbl1_u T_TABLE1;
tbl1_i T_TABLE1;
This table will keep growing and at the end, will be used in FORALL loop to do insert or update on TABLE_1.
Now there might be cases, where I want to delete a certain element. So i am planning to create a procedure, which will take the KEY (unique) and matched the element if that key is found
PSEDUO CODE
FOR i in tbl1_u.FIST..tbl1_u.LAST
LOOP
if tbl1_u(i).key = key then
tbl1.delete(i);
end if;
END LOOP;
My question is,
Once i delete the particular element, would be collection adjust automatically i.e., the index i would be replaced by next element or would that particular index will remain null/invalid and could possibly give me exception if i use it in FORALL INSERT/UPDATE?
I don't think that i can pass TABLE_1%ROWTYPE object to a procedure, do i have to create a record type ?
Any other tip regarding managing collection for bull delete/update/insert would be appreciate. Remeber, I would be dealing with 2 tables, if i am inserting/updating in table_1 then it means i am deleting it from table_2 and vice-versa.
Given that TABLE_1.KEY is unique you might consider using that as the index to your associative arrays. That way you can delete from the collections using the KEY value, which according to the pseudocode is available when doing the deletions. This would also save you having to iterate through the table to find the KEY you want, as the KEY would be the index - so your "deletion" pseudo-code would become:
tbl1_u.delete(key);
To answer your questions:
Since you're using associative arrays, when an element is deleted there is no "empty" space in the collection. The indexes for the elements, however, don't actually change. Therefore you need to use the collection.PRIOR and collection.NEXT methods to loop through the collection. But again, if you use the KEY value as the index you may not need to loop through the collections at all.
You can pass a TABLE_1%ROWTYPE as a parameter to a PL/SQL procedure or function.
You might want to consider using a MERGE statement which could handle doing the inserts and updates in one step. This might allow you to maintain only a single collection. Might be worth looking in to.
Share and enjoy.

Alternative to search through a packed+unpacked array in systemverilog

I have this strange situation where i am currently doing this:
if (!this.randomize(delay) with {delay inside {strm};})
......
where
rand bit [2:0] delay;
bit [15:0] strm [bit [15:0]];
Now I want this delay to go in round robin from 0->....->7->0 and so on, but it should satisfy the condition that it should be present in strm. So I want something like
while (delay not in strm) begin
delay+=1;
end
Other than going though each and every index (2^16-1) is there any other way of finding if it exists in this packed+unpacked array? Thanks in advance!
If you are not aware, you are declaring strm as an associative array (aka a hash), where the key and the data are both 16 bit values.
If you want strm to be a fixed-size 2^16 entry array of 16-bit values, the declaration would be:
bit[15:0] strm [2**16];
With associative arrays you can use array.exists(key) to determine if the key is in the array. But it seems this may not be what you are trying to do.
With unpacked arrays, you can use the inside operator to test for set membership. But my simulator (Incisive) does not like this usage outside of a randomization call. So you may need to search for it yourself. However you don't have to iterate the entire array if you sort it first. And you can do that with array.sort().
I would also point out that you are looking for a 3-bit value in some sort of array of 16-bit values. This doesn't really make sense, so you may want to clarify your question.

Resources