aslze / asl

A compact C++ cross-platform library including JSON, XML, HTTP, Sockets, WebSockets, threads, processes, logs, file system, CSV, INI files, vectors and matrices, etc.
Other
69 stars 17 forks source link

add method for Dic<Var>, adds to other Dic... #22

Closed dezashibi closed 1 year ago

dezashibi commented 1 year ago

Hi, I saw something that I think is an undefined behavior. imagine this:

struct info {
    Dic<Var> prop{};
    int number{0};
};

std::map<int, info> information = {
    /* it has a bunch of information */
};

information[2].prop.add({"some_key", "value"});

I saw this caused problem in Array.h that is from add function in Map. what I observed is one of these adds has added the given Dic to another member of the std::map if that make sense. which causes other calling add for the other member to fail with undefined behavior and memory problem.

other information is that the keys in the information are built from code points of a String characters. I tested the count and number are correct.

I've no clue for more debugging, but am open to contribute and/or any task or help that you may need.

aslze commented 1 year ago

I don't really understand, but maybe you should not be using the add() method that way.

To add items to a map/dic I use the more intuitive operator[] (both to read and write, if key does not exist, it is added):

map[key] = value;

In your case:

information[2].prop["some_key"] = "value";

Or you could use the set() method, which will do the same.

information[2].prop.set("some_key", "value");

The add() method is used to merge maps, so to say. It adds all key/values from a map to another map, extending it.

I'm not sure what it is doing in your case. In theory it first constructs a Dic from {"some_key", "value"} but I don't know how, and then appends it to prop. I will check anyway.

Also, what is the content of /* it has a bunch of information */? (a bit of it at least).

dezashibi commented 1 year ago

I got what you mean and yes the example need to be more specific I agree. my use case was in fact like

information[2].prop.add({{"some_key", "value"}, {"some_key2", "value2"}, {"some_key3", "value3"}});

and I expected the keys from the given Dic to be replaced or added to the prop.

about /* it has a bunch of information */, just a couple if initializations like this:

std::map<int, info> information = {
   {1, {{}, 10}},
   {2, {{}, 20}},
   // ...
};

let me know if it still needs more explanations.

aslze commented 1 year ago

And, BTW, keys are unique, so adding a value to an existing key will rewrite it (with operator[], with set() or with add()).

Dic<int> a{ {"a", 1}, {"b", 2} };

Dic<int> b{ {"b", 3}, {"c", 4} };

a.add(b);

Now a contains

a: 1     // this comes from a
b: 3     // a already had "b", so it is overwritten
c: 4     // this comes from b
aslze commented 1 year ago

OK, I see. I'll do some tests later today.

dezashibi commented 1 year ago

yes uniqueness is actually a good thing and what I expected, and thanks, again let me know if anything I can do in the meanwhile.

dezashibi commented 1 year ago

a quick update that may help, though I'm not sure if this is relevant or not, the way I populate the information is like this:

std::map<int, info> information;

for (auto ch&: String("\\._()[]{}«»").chars())
{
    information[ch]={{}, 1};
}

I'm almost sure that chars() generates correct number of elements with correct data, I'm almost sure also about the iterator itself but still I thought worth to be mentioned.

aslze commented 1 year ago

I cannot reproduce the problem. What is supposed to happen and when exactly?

I tried this, which prints the contents at the end. And it goes as expected.

        for (auto& ch : String("\\._()[]{}«»").chars())
        {
            information[ch] = { {}, 1 };
            information[ch].prop.add({ { "key1", "value1" },
                                       { "key2", "value2" },
                                       { "key3", "value3" },
                                       { "key4", "value4" },
                                       { "key-" + String(ch), "value-" + String(ch) } });
        }

        information[1].prop.add(
            { { "key11", "value11" }, { "key12", "value12" }, { "key13", "value13" }, { "key14", "value14" } });
        information[2].prop.add(
            { { "key21", "value21" }, { "key22", "value22" }, { "key23", "value23" }, { "key24", "value24" } });
        information[3].prop.add(
            { { "key31", "value31" }, { "key32", "value32" }, { "key33", "value33" }, { "key34", "value34" } });

        for (auto inf : information)
        {
            printf("[%i]\n", inf.first);
            for (auto e : inf.second.prop)
            {
                printf("%s => %s\n", *e.key, *e.value);
            }
        }
dezashibi commented 1 year ago

If this works as you mentioned well that's a good sign, I'm going to completely isolate my use case and re-test to see why I cannot get the expected result.

aslze commented 1 year ago

And well, a Var can be different types, so values do not need to be strings:

            information[ch].prop.add({ { "key1", ch },        // int
                                       { "key2", ch * 1.5 },  // double
                                       { "key3", ch > 100 },  // bool
                                       { "key4", "value4" },  // string
                                       { "key-" + String(ch), "value-" + String(ch) } });

Then when printing this would need toString():

    printf("%s => %s\n", *e.key, *e.value.toString());
dezashibi commented 1 year ago

ok, finally found the problem, I was passing a const info& to another function and that function was suppose to add new elements to the map with the passed info and the problem was pointing to same info.prop, I just used clone() for it and the problem solved. thanks for your time and hints. have a good one