toml11 icon indicating copy to clipboard operation
toml11 copied to clipboard

Populating the toml table as required by the user

Open ravipathuri opened this issue 3 years ago • 5 comments

Hello I currently use v3.6.0 version of the tomll11 header only library. The parsing part work as expected. But i see few issues w.r.t populating the toml table content in the order as required by the user. This is a demo program #include "toml.hpp" // that's all! now you can use it. #include #include #include int main() { toml::value data{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}}; data["hoge"] = "piyo"; std::stringstream ss; ss << std::setw(0) << data; std::cout<<"Actual toml content\n"<<ss.str(); return 0; } The output is Actual toml content hoge = "piyo" baz = "qux" foo = 42 bar = 3.14

It should have been Actual toml content hoge = "piyo" baz = "qux" bar = 3.14 foo = 42

Any reason for this behaviour? over-riding the type the std::map will just place the keys in alphabetical order(sorted manner). But in my case i want the key value pairs to be in the order as they are passed. How can we achieve this? Please give your inputs

ravipathuri avatar Apr 14 '21 07:04 ravipathuri

Hi,

In toml11, the underlying map type is responsible for the order of key-value pairs. By default, it uses std::unordered_map that is essentially does not preserve the order because it uses hash value, so it is the reason why the serialization result changes the order (note that the TOML spec says that it is designed to map to a hash table.)

To keep the order of the key-value pairs in a table, you need to use order-preserving map class, like https://github.com/Tessil/ordered-map. This map class keeps the insertion order. So,

#include "toml.hpp"
#include "tsl/ordered_map.h"
#include <iostream>

int main()
{
    using value_type = toml::basic_value<toml::preserve_comments, tsl::ordered_map>;
    value_type v;
    v["hoge"] = "piyo";
    v["baz"]  = "qux";
    v["bar"]  = 3.14;
    v["foo"]  = 42;

    std::cout << v << std::endl;
    // hoge = "piyo"
    // baz = "qux"
    // bar = 3.14
    // foo = 42
    //
    return 0;
}

You can also parse a file keeping the order of key-value pairs in the following way.

#include "toml.hpp"
#include "tsl/ordered_map.h"
#include <iostream>

int main()
{
    auto data = toml::parse<toml::preserve_comments, tsl::ordered_map>("issue157.toml");
    data["hoge"] = "piyo";
    std::cout << data << std::endl;
    return 0;
}

Note that, by doing this, the hoge key is assigned to the table as the last element.

ToruNiina avatar Apr 14 '21 07:04 ToruNiina

Thanks for the suggestion :) . This works when a simple application using g++ (on ubuntu) is built and tested. But when I try to incorporate the above logic in my application(QNX) using the alias using tomlTableType = toml::basic_value<toml::preserve_comments, tsl::ordered_map>; I get the below error error: no type named 'value_type' in 'struct std::__1::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator >, toml::basic_value<toml::preserve_comments, tsl::ordered_map> > > >::rebind_alloc<tsl::detail_ordered_hash::bucket_entry >' typedef typename __pointer_type<value_type, allocator_type>::type pointer;

error: no type named 'value_type' in 'struct std::__1::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator >, toml::basic_value<toml::preserve_comments, tsl::ordered_map> > > >::rebind_alloc<tsl::detail_ordered_hash::bucket_entry >' typedef typename __const_pointer<value_type, pointer, allocator_type>::type const_pointer;

I am not sure if it is a general issue. Can you please suggest on how i can resolve this

ravipathuri avatar Apr 14 '21 18:04 ravipathuri

The following code does not reproduce the error you reported. I compiled with g++-10 -std=c++11 issue157.cpp -Wall -Wextra -Wpedantic -O2. And I don't know if I can do anything about a problem.

#include "toml.hpp"
#include "ordered-map/include/tsl/ordered_map.h"
#include <iostream>

int main(int argc, char** argv)
{
    using tomlTableType = toml::basic_value<toml::preserve_comments, tsl::ordered_map>;

    tomlTableType t;
    t["foo"] = "bar";

    return 0;
}

I think the error may be caused by the inclusion or definition order. You can try several patterns.

ToruNiina avatar Apr 16 '21 04:04 ToruNiina

To chime in: I do think it is nice to have some sort of canonical output that is always the same for the same input (for many cases, versioning etc.). So e.g. making all tables have a defined alphabetical order would be a great define to have as behavior (or as output stream option like precision/inline tables)

monkeydom avatar May 31 '21 12:05 monkeydom

#include "toml.hpp" #include "tsl/ordered_map.h" #include

int main() { using value_type = toml::basic_value<toml::preserve_comments, tsl::ordered_map>; value_type v; v["hoge"] = "piyo"; v["baz"] = "qux"; v["bar"] = 3.14; v["foo"] = 42;

//hello, with the similar question
//value_type& v = toml::find<toml::table>(data, testTable);  this has error, so how to get the reference to the table?
//v[]="";

}

NaturalUser avatar Jan 15 '23 07:01 NaturalUser