jimporter/bencode.hpp

Feature request getType()

heretic13 opened this issue · 4 comments

Hello.

I would like to get functionality that let me know the type contained in bencode::data.
For example, the following set of functions:
bool isInteger (const bencode::data &);
bool isString (const bencode::data &);
bool isDictionary (const bencode::data &);
....

But since bencode::data is boost::variant, it's probably easier to do this:

enum BencodeTypes // this type is not defined in your library
{
   Integer,
   String,
   List,
   Dictionary
};

bencode::data dt;

if (dt.which () == Integer)
{
   // do something
}

Does boost::variant::type() give you what you want? It should return the std::type_info for the active type, assuming you're building with RTTI enabled. If not, could you elaborate on what doesn't work with the Boost API? If there's some major gap that Boost's API doesn't cover, then I agree we should add something here.

Another option that might be useful (though I'm not sure) would be something that returns the type of the root element for an unparsed string of bytes. That really just requires looking at the first character, which would be pretty efficient compared to parsing the whole string. I'm leaning softly towards "this isn't generally useful" though...

There are some recommendations that say that using RTTI wherever it is required and not required is evil!

This task would perfectly well be resolved through "enum BencodeTypes" (or some other nice name), as indicated in my example above.

The goal is just to know the correct type stored in boost::variant and write the appropriate processing logic. I admit that in the future you will be able to change the order of the records in your boost::variant, which can broke aliens code that will use it.

Currently:

using data = boost::make_recursive_variant<
integer,
string,
std::vectorboost::recursive_variant_,
std::map<string, boost::recursive_variant_>

::type;

Maybe in future:

using data = boost::make_recursive_variant<
string,
integer,
std::vectorboost::recursive_variant_,
std::map<string, boost::recursive_variant_>

::type;

And now the code that can be broken (after changing the order of the definitions in boost :: variant):

bencode::data dt;
....

if (dt.which () == 0)
{
long long someInt=boost::get(dt);
// do something with 'someInt'
}
.

One of the solutions:

enum BencodeTypes // this type is not defined in your library
{
Integer,
String,
List,
Dictionary
};

if (dt.which () == BencodeTypes::Integer)
{
long long someInt=boost::get(dt);
// do something with 'someInt'
}

After changing the library:

enum BencodeTypes // this type is not defined in your library
{
String,
Integer,
List,
Dictionary
};

using data = boost::make_recursive_variant<
string,
integer,
std::vectorboost::recursive_variant_,
std::map<string, boost::recursive_variant_>

::type;

You do not need to change the third-party code, just recompile.

if (dt.which () == BencodeTypes::Integer)
{
  long long someInt=boost::get(dt);
  // do something with 'someInt'
}

If that's what you're trying to do, I'd recommend something like the following:

if(auto value = boost::get<bencode::integer>(&dt)) {
  // `value` is now a pointer to an integer, assuming `dt` holds an integer
}

Or, even better:

try {
  auto value = boost::get<bencode::integer>(dt);
  // do something with the value
} catch(boost::bad_get) {
  // `dt` didn't hold an integer!
}

For more complicated cases, a visitor is probably the best solution, but that's more verbose for the simple case.

Closing based on my comment above; if that's insufficient, feel free to reply and we can discuss further options.