Solidity: Dedupping string keys inside a pure function - solidity

I am trying to define a mapping to use inside a function as a means of quickly determining whether a key exists. I realize I could also use an array and loop thorugh it but that seems like it might get expensive. But that you can't create mappings dynamically, and if I create a state variable for the purpose, then I have the problem of clearing state between calls to this function which makes it pricey.
Here is what I was tyring to do, any suggestions for the most efficient method to dedupe a set of strings inside a pure function?
function dedupe(string[] memory keys) public pure returns(string[] memory) {
string[] memory deduped;
mapping(string=>bool) map;
string memory ikey;
for(uint i=0; i<keys.length; i++) {
ikey = keys[i];
if (!map[ikey]) {
map[ikey]=true;
deduped.push(ikey);
}
}
return deduped;
}

Related

How to swap array elements using destructuring in Solidity?

I want to delete data from an array. But deleting data from a particular array index creates a gap in the array. Hence, I am swapping the array[i] with array[array.length-1] and popping out the array. I tried to do it with a destructuring technique that is supported in Solidity yet it turns out the values do not tend to swap. While swapping using the "temp" variable seems to work perfectly fine but it consumes more gas.
There's a warning that solidity throws which I am not able to understand.
Warning: This assignment performs two copies to storage. Since storage copies do not first copy to a temporary location, one of them might be overwritten before the second is executed and thus may have unexpected effects. It is safer to perform the copies separately or assign to storage pointers first.
Can anyone help?
Please find the code below:
struct Details{
uint256 id;
address walletAddress;
string fullName;
uint256 phoneNumber;
string residentialAddress;
}
Details [] public userDetails;
function deleteData(uint256 _id) public onlyOwner returns(string memory){
for(uint256 i=0;i<userDetails.length;i++)
{
if (userDetails[i].id==_id){
(userDetails[i],userDetails[userDetails.length-1])=(userDetails[userDetails.length-1],userDetails[i]);
userDetails.pop();
}
}
}
You can just assign the last item to the place of the deleted one (effectively duplicating the last item for the moment), and then delete the last item.
if (userDetails[i].id == _id) {
userDetails[i] = userDetails[userDetails.length-1];
userDetails.pop();
break;
}

How to efficiently marshal array of objects to native function using C++/CLI

I have array of objects holding primitive types and enums; how do I marshal a pointer to this data to a native function with the signature native_func(void* ptr[]).
array<System::Object^>^ values = gcnew array<System::Object>(64);
// ... populate the managed array with primitives ...
// data is pinned and won't be moved by the GC
pin_ptr<object> pinned = &values[0];
// not sure what do here... data is corrupted in the native code
native_func((void**)pinned);
Thanks!
EDIT. My second attempt was to do the following:
pin_ptr<object> pinned = &values[0];
void* testArray[64];
for (auto i = 0; i < values->Length; i++)
{
testArray[i] = (void*)Marshal::UnsafeAddrOfPinnedArrayElement(values, i);
}
native_func(testArray);
Now, the addresses stored in testArray are getting passed correctly to the native side but the contents of the memory is not what I am expecting. What am I doing wrong now?
Enums are not blittable so marshaling an array of objects require special consideration (i.e. you can't just pin_ptr the array and pass it over the native/managed boundary). I decided to use a VARIANT to hold the primitive & enum values and did so with the following code:
// allocate a managed array of size 64 (it's enough for my application)
array<System::Object^>^ values = gcnew array<System::Object>(64);
// stack allocate a native array of size 64
VARIANT nativeValueArray[64] = {};
// ... populate the managed array ...
for (auto i = 0; i < values->Length; i++)
{
Marshal::GetNativeVariantForObject(values[i], (IntPtr)(void*)&nativeValueArray[i]);
}
// pass the array of native VARIANTS to the native function "native_function"
native_function(nativeValueArray);
The native function's signature became
void native_function(VARIANT values[]);
There might be a more efficient way to do this but this is what I was able to come up with. Please let me know if you have a more efficient way to accomplish what am I doing.

Iterate over dlang struct

I have a struct that looks something like this:
struct MultipartMessage {
ubyte[] mime, data;
Header header;
void setSender(string sender) {
header.sender = sender;
}
void setId(int id) {
header.id = id;
}
}
and I would like to iterate over it, in another class with something like this:
struct Socket {
...
void send(MultipartMessage msg) {
foreach (part; msg) {
sendPart(part);
}
}
...
}
Is this possible? I'd like to use something analogous to Python's __iter__ in the MultipartMessage that can return the fields in a specific order, and ideally even run some additional code, like header.serialize().
Ideally I would add a function to MultipartMessage that would look something like this (pseudocode):
ubyte[] __iter__() {
yield mime;
yield data;
yield header.serialize(); //header.serialize returns a ubyte[]
}
Use tupleof:
foreach (ref part; msg.tupleof)
sendPart(part);
This will call sendPart with mime, data and header (the struct's fields, in the order they were declared). You can filter fields by checking their type with e.g. static if (!is(typeof(part) == Header)).
To get the field's name, you can use __traits(identifier):
foreach (i, ref part; msg.tupleof)
writeln(__traits(identifier, msg.tupleof[i]));
(__traits(identifier, part) would return part.)
There's also __traits(allMembers), which also returns methods.
The closest thing to what you want is probably opApply.
See http://dlang.org/spec/statement.html , Section Foreach over Structs and Classes wit opApply
This will work:
int opApply(int delegate(ref ubyte[]) dg) {
int result = 0;
result = dg(mime);
result = dg(data);
ubyte[] header_bytes = header.serialize();
result = dg(header_bytes);
return result;
}
There are several ways to do iterate over objects in D.
One is to implement the InputRange API. Input ranges are similar to iterators, but have a different API. Implementing a range interface means that you can use all of the std.range/std.algorithm functions on your object, such as map, array, joiner and so on.
D doesn't have an __iter__ function to get an iterator from arbitrary collections, so you will need to implement a function that returns an input range.
import std.range;
auto bytes() {
return chain(mime, data, header.serialize);
}
This will return a ubyte input range, consisting of the bytes in mime, followed by the bytes in data, then in header.serialize.
You can also implement the opApply method on your struct. opApply will only work with foreach, so you can't use range methods with it, but it allows you to do things like execute the loop body in separate threads.
The gist of opApply is that D passes the loop body to opApply as a function; that is, foreach(x; myObj) { body } is transformed into myObj.opApply((x) { body }).
void opApply(void delegate(ubyte[] part) loopbody) {
loopbody(mime);
loopbody(data);
loopbody(header.serialize());
}
However, instead of either of those options, I recommend that you implement a function on your object that takes an output range and writes the data to it.
An output range is an object that accepts other objects, and does something to them. In this case, the output range should accept ubytes, making it similar to an output stream.
void serialize(Range)(ref Range outRange) if(isOutputRange!(Range, ubyte)) {
put(outRange, mime); -- `put` simply feeds data into the output range
put(outRange, data);
header.serialize(outRange); // No longer have to allocate/return a ubyte array
}
Example usage, that stores the output into an Appender, which can be converted into an array:
import std.array;
auto serializedDataAppender = appender!ubyte();
myMsg.serialize(serializedDataAppender);
auto serializedData = serializedDataAppender.data;
If you implement an output range on top of your socket, then that means that the output range solution does not have to allocate any memory from the heap.
Check out the Programming in D book (specifically, the Ranges and More Ranges sections) for info on how to implement your own ranges.

How to convert valueForKeyPath in swift

My old function in objective c is
+ (NSUInteger)getNumberOfDistinctUsers:(NSArray *)users {
NSArray* usersAfterPredicate = [users valueForKeyPath:#"#distinctUnionOfObjects.userName"];
return [usersAfterPredicate count]; }
How do I convert this in swift, I was trying to something like this but its crashing "Could not cast value of type 'Swift.Array'to 'Swift.AnyObject'"
static func getNumberOfDistinctUsers(users: [ICEPKReferenceDataUser]) -> Int {
var retval : Int = 0
if let usersAfterPredicate = (users as! AnyObject).valueForKeyPath("#distinctUnionOfObjects.userName") {
retval = usersAfterPredicate.count
}
return retval
}
Can I solve this problem using filter, map or Reduce? I am just trying to find out distint users in users array using the property username.
Edit* brute force way
static func getNumberOfDistinctUsers(users: [ICEPKReferenceDataUser]) -> Int {
var retvalSet : Set<String> = []
for user in users {
retvalSet.insert(user.userName)
}
return retvalSet.count
}
As you suspect, you can simplify the code with a simple map:
static func getNumberOfDistinctUsers(users: [ICEPKReferenceDataUser]) -> Int {
return Set(users.lazy.map{$0.userName}).count
}
This uses the fact that you can initialize a Set using any other sequence.
I added lazy in there to avoid creating an extra copy of the array. It'll work with or without, but I expect it to be much more memory efficient this way. Array.map creates another Array. array.lazy.map return a lazy collection that computes values as requested.
That said, I don't know that my approach is dramatically better than your "brute-force" way. It's not obvious which is easer to read or maintain. I have a fondness for the map approach, but it can be a tradeoff (I had to know to add lazy for instance, or I could have allocated significant memory if this were a large array). Your code makes it very clear what's going on, so I don't think there's any problem that has to be solved there.
If you really wanted to use KVC, you'd need to convert your array to an NSArray, not an AnyObject, but I suspect that the above code is much faster, and is clearer and simpler, too, IMO.

When does JNI decide that it can release memory?

When I return a direct ByteBuffer to JNI, how long until it can get reclaimed by the JVM/GC?
Suppose I have a function like this:
void* func()
{
[ ... ]
jobject result = env->CallStaticObjectMethod(testClass, doSomethingMethod);
void* pointerToMemory = env->GetDirectBufferAddress(result);
return pointerToMemory;
}
The JVM can't possibly know how long I'm going to use that pointerToMemory, right? What if I want to hold on to that address and the corresponding memory for a while?
Suppose I want to circumvent this issue and return a byte[] from Java to JNI like this:
ByteBuffer buf;
byte[] b = new byte[1000];
buf = ByteBuffer.wrap(b);
buf.order(ByteOrder.BIG_ENDIAN);
return buf.array();
AND THEN do the same as above, I store a pointer to that byte[] and want to hold on to it for a while. How / when / why is the JVM going to come after that backing byte[] from Java?
void* function()
{
jbyteArray byteArr = (jbytearray)env->CallStaticObjectMethod(testClass, doSomethingMethod);
jbyte *b= env->GetByteArrayElements(byteArr, 0);
return b;
}
The short answer is: If the function implements a native method, the pointer will be invalid as soon as you return.
To avoid this, you should get a global reference for all objects that you intend to keep valid after returning. See the documentation on local and global references for more information.
To understand better how JNI manages references from native code, see the documentation on PushLocalFrame/PopLocalFrame.