Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It's not a bug. How to count elements of nested array? #15

Closed
clabnet opened this issue Sep 29, 2021 · 8 comments
Closed

It's not a bug. How to count elements of nested array? #15

clabnet opened this issue Sep 29, 2021 · 8 comments

Comments

@clabnet
Copy link

clabnet commented Sep 29, 2021

Hi,
on this array
"vec" : [
{ "key" : 4, "value": 1.0 },
{ "key" : 5, "value": 2.0 },
{ "key" : 6, "value": 3.0 }
]
how to know the number of elements ?
On this sample, 3. Thank's

@jorgen
Copy link
Owner

jorgen commented Sep 29, 2021

Hi, thank you for the query!

There are multiple ways of finding the size of vec, but I think the easiest and most versatile is to use a std::vector. Please see the following example:

#include <string>
#include <json_struct.h>

const char json[] = R"json(
{
  "vec" : [
    { "key" : 4, "value": 1.0 },
    { "key" : 5, "value": 2.0 },
    { "key" : 6, "value": 3.0 }
  ]
}
)json";

struct VecMember
{
  std::string key;
  double value;

  JS_OBJ(key, value);
};

struct JsonObject
{
  std::vector<VecMember> vec;
  JS_OBJ(vec);
};


int main()
{
    JsonObject obj;
    JS::ParseContext parseContext(json);
    if (parseContext.parseTo(obj) != JS::Error::NoError)
    {
        std::string errorStr = parseContext.makeErrorString();
        fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str());
        return -1;
    }

    fprintf(stdout, "Vec has size %zu\n", obj.vec.size());

    return 0;
}

Hope this answers the question. If it does please close the issue.

@clabnet
Copy link
Author

clabnet commented Sep 29, 2021

Hi @jorgen , thank you for your fast response.
Your reply is very valuable, but my problem is a little too complicated.
I try to be more precise. My json_data is contained into config.json file:

{
    "webInterface": "localhost",
    "......"; "......",
    "moduleList": [
        { "id": 0, "name": "MAINTENANCE" },
        { "id": 1, "name": "CORE" },
        { "id": 2, "name": "BLA BLA" }
    ]
}

and my struct is here : https://pastebin.com/embed_js/fp7WYs6c
Please note on this code the struct TypeHandler<ModuleList<T>> part and the MODULELIST_COUNT define.

When I read the config.json file,

   std::ifstream ifs(config_file.c_str());
   if (!ifs) {
                throw std::invalid_argument("Can't open app config file " + config_file);
   }
   std::string json_data((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
   spdlog::trace(json_data);

I can't parse securely the entire json into Config struct because I can't know how much elements of array the user can be defined. The user can be define one, two, "n" element on moduleList array.

The final goal:
I would remove from the source code the MODULELIST_COUNT define constant, but I don't know.

Sorry for the long post and thank you for your time.

Regards,

@jorgen
Copy link
Owner

jorgen commented Sep 29, 2021

right! ok. so you want to have a static sized buffer, but want to populate it with dynamic data? so I assume you will have som size variable keeping count of how much of the buffer is filled up? Since you have already a type handler we can modify it "by copying the array type handler spesialisation" and make it fit your needs. I have adjusted the example, does this fit the bill? We have some more options if it doesn't do what you want it to :D

#include <string>
#include <json_struct.h>

const char json[] = R"json(
{
  "vec" : [
    { "key" : 4, "value": 1.0 },
    { "key" : 5, "value": 2.0 },
    { "key" : 6, "value": 3.0 }
  ]
}
)json";

struct VecMember
{
  std::string key;
  double value;

  JS_OBJ(key, value);
};


struct ModuleList
{
  enum
  {
    ReservedSize = 16
  };
  VecMember modules[ReservedSize];
  int size = 0;
};

namespace JS
{
template <>
struct TypeHandler<ModuleList>
{
  static inline Error to(ModuleList &to_type, ParseContext &context)
  {
    if (context.token.value_type != Type::ArrayStart)
      return JS::Error::ExpectedArrayStart;

    context.nextToken();
    for (size_t i = 0; i < ModuleList::ReservedSize; i++)
    {
      if (context.error != JS::Error::NoError)
        return context.error;
      if (context.token.value_type == Type::ArrayEnd)
      {
        to_type.size = i;
        break;
      }
      context.error = TypeHandler<VecMember>::to(to_type.modules[i], context);
      if (context.error != JS::Error::NoError)
        return context.error;

      context.nextToken();
    }

    if (context.token.value_type != Type::ArrayEnd)
      return JS::Error::ExpectedArrayEnd;
    return context.error;
  }

  static inline void from(const ModuleList &from_type, Token &token, Serializer &serializer)
  {
    token.value_type = Type::ArrayStart;
    token.value = DataRef("[");
    serializer.write(token);

    token.name = DataRef("");
    for (size_t i = 0; i < from_type.size; i++)
      TypeHandler<VecMember>::from(from_type.modules[i], token, serializer);

    token.name = DataRef("");
    token.value_type = Type::ArrayEnd;
    token.value = DataRef("]");
    serializer.write(token);
  }
};
} // namespace JS

struct JsonObject
{
  ModuleList vec;
  JS_OBJ(vec);
};


int main()
{
    JsonObject obj;
    JS::ParseContext parseContext(json);
    if (parseContext.parseTo(obj) != JS::Error::NoError)
    {
        std::string errorStr = parseContext.makeErrorString();
        fprintf(stderr, "Error parsing struct %s\n", errorStr.c_str());
        return -1;
    }

    fprintf(stdout, "Vec has size %zu\n", obj.vec.size);

    return 0;
}

@jorgen
Copy link
Owner

jorgen commented Sep 29, 2021

Hi! I just added a new type to json_struct called JS::ArrayVariableContent. It is basically the code above but removes the need for a more advanced type handler.

https://github.com/jorgen/json_struct/blob/master/tests/json-struct-array-varlength.cpp

@jorgen
Copy link
Owner

jorgen commented Sep 30, 2021

Can I close this issue now?

@clabnet
Copy link
Author

clabnet commented Sep 30, 2021

Sorry for delay, tomorrow I send you my solution.

@clabnet
Copy link
Author

clabnet commented Oct 1, 2021

Many thanks for your proposal, but I have found a short road.
I have set MODULELIST_COUNT to 32 (fortunately I know how the max number of elements the user can create)
and defined

        std::vector<Module> moduleList;

It work as is.

Good to hear you, and many thanks @jorgen.

Best regards.

@clabnet clabnet closed this as completed Oct 1, 2021
@clabnet
Copy link
Author

clabnet commented Oct 1, 2021

closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants