2

I'm trying to store really large value to a table in field uint128_t, but I get this

"integer literal is too large to be represented in any integer type"

error when trying to compile. When i insert some small value and copy its value from db it is for example "0xf1a91a3b000000000000000000000000" and I try to hardcode that value into code like this:

uint128_t tmp = 0xffc91a3b000000000000000000000000; 

I get same error during wast creation. I need this value for fast searching through db, and I can not store it as a string because string is not supported for index key.

Do you guys have any ideas?

Cheers

EDIT: I can store it manually with cleos push action, just can not compile it because i get this error. So it can be stored but can not be in source code, and I need it to be in source code.

EDIT: The problem is because the compiler won't let you specify a literal value for an integer bigger than uint64_t. Setting a uint128_t from another variable like the action params, or from an arithmetic operation between smaller uint64_t integers will work well though.

0

3 Answers 3

1

As I could find, apparently the compiler will allow you to use uint128_t variables but not literals, since it doesn't support expressing literal ints bigger than 64 bits it seems. So if you want to assign a hardcoded literal to a uint128_t you will need some workaround. There are some libraries and maybe macros that allow you to express 128 bit int literals in the code directly. I'm not sure if the EOSIO code ships with a macro or something for this, and I don't think it makes sense to include another library just to do this, so in my research I found a workaround:

uint64_t high = <first digits of the number>;
uint64_t low = <last digits of the number>;
uint128_t number = ((uint128_t)1000000000000 * high) + low;

I tried it out and it works quite well. I switched the uint128_t for uint64_t and printed it out and it was overflowing the 64 bits, it was printing a different number. With uint128_t it stored and printed the exact number I was constructing. You can play around with the amount of zeros in the multiplier to suit your needs and print the result out to make sure you're generating the right number you wanted.

1

So one way to address this is by using a hash table. In this case, regardless of how big your index is, it can be hashed into a fixed-size key. However, I'm not sure EOSIO provides a hashtable implementation to communicate with their multi-index API, but you can create your own ad-hoc implementation by doing something like this:

#include<string>
#include<math.h>
#include<eosiolib/eosio.hpp>
#include<eosiolib/crypto.h>

using std::string;
using eosio::contract;
using eosio::print;
using eosio::multi_index;


class hashtable : contract {
    public:
        hashtable(account_name account) : 
            contract(account),
            tab(_self, _self)
            {}

        void store(account_name account, string key, string value) {
            uint128_t int_key = _hash(key);
            eosio_assert(tab.find(int_key) == tab.end(), "Key already used");
            tab.emplace(account, [&](auto &t) {
                t.key = int_key;
                t.val = value;
            });
        }

        void get(string key) {
            uint128_t int_key = _hash(key);
            auto iter = tab.find(int_key);
            eosio_assert(iter != tab.end(), "Key not found");
            print(iter->val);
        }
    private:
        struct my_table {
            uint128_t key;
            string val;
            auto primary_key() const { return key; }
        };

        uint128_t _hash(string key) {
            checksum256 result;
            sha256(&key[0], key.size(), &result);
            uint128_t my_number = 0;
            for(char i = 0; i < 32; i++) {
                my_number = my_number + pow(10, i) * result.hash[i];
            }
            return my_number;
        }

        multi_index<N(my_table), my_table> tab;
};

EOSIO_ABI(hashtable, (store)(get))

In this example, I used a uint128_t for the key to make collisions improbable, but you can also have it as a uint64_t if you want to save RAM.

This can allow you to fast search through your table using only a string even if the table doesn't know you're using a string.

8
  • Yes, but what if number is bigger than uint64_t? I need uint128_t...
    – Bida
    Commented Jul 25, 2018 at 17:27
  • do you need to retrieve the id or just be able to index with the id and retrieve back the values associated with that record in the table? it the latter, the function can be considered a hash function that let you do that but won't let you get back the message from the hash value
    – confused00
    Commented Jul 25, 2018 at 17:54
  • not a very good hash function though cause it has collisions for numbers that have the and first 13 chars. would a hash function work for you though? I can edit if so otherwise I'll delete
    – confused00
    Commented Jul 25, 2018 at 18:00
  • yes i think so, operations i have are: -save it with this large int value -query by this large int value so if i can save this 0x..... string or some sort of 16 bytes structure and then always query it without collisions i think it is enough... thanks for answers
    – Bida
    Commented Jul 25, 2018 at 18:04
  • it would be helpful if you edit hash function, tnx :)
    – Bida
    Commented Jul 25, 2018 at 20:00
1

The question asks how to create a literal. Managing to assign a number to a variable is not quite the same. If you have a true literal, an optimizing compiler will be able to fold that into the code. But if you have a variable, the compiler will be forced to load from memory on every access, because a variable might change.

You can create a true literal using #define macros. Here's an example from my code:

#define LIT128(HI,LO) ((((__uint128_t) HI) << 64) | LO)
#define LEFT_ROW  LIT128(0x0100200400801002,    0x0040080100200400)

This is in the inner loop of a program I am writing to solve a pentomino problem. The literal version delivers about 10% more solutions per second. This is pretty significant for me, because I estimate the number of solutions to be 10 billion = several months of CPU.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.