Loki-Astari / ThorsSerializer

C++ Serialization library for JSON

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Maximum number of levels/depth?

ripe909 opened this issue · comments

Is there maximum number of levels that can be encoded in the JSON output?

I am creating a JSON tree structure of vectors and pointers that goes down 9 levels. On the ninth level I have a member std::array. As soon as I jsonExport at that level, the export hangs. If I move the std::array one level up, it works as expected.

class level8_cont
{
public:
	std::array<int, 3> array9 = { 1, 2, 3 };
};
class level7
{
public:
	level7()
	{
		levels8.emplace_back();
	}
	std::vector<level8_cont> levels8;
};
class level6_cont
{
public:
	level6_cont()
	{
		nextLevel7 = new level7();
	}
	level7 *nextLevel7;
};
class level5
{
public:
	level5()
	{
		levels6.emplace_back();
	}
	std::vector<level6_cont> levels6;
};
class level4_cont
{
public:
	level4_cont()
	{
		nextLevel5 = new level5();
	}
	level5 *nextLevel5;
};
class level3
{
public:
	level3()
	{
		levels4.emplace_back();
	}
	std::vector<level4_cont> levels4;
};
class level2_cont
{
public:
	level2_cont()
	{
		nextLevel3 = new level3();
	}
	level3 *nextLevel3;
};
class level1
{
public:
	level1()
	{
		levels2.emplace_back();
	}

	std::vector<level2_cont> levels2;
};

ThorsAnvil_MakeTrait(level1, levels2);
ThorsAnvil_MakeTrait(level2_cont, nextLevel3);
ThorsAnvil_MakeTrait(level3, levels4);
ThorsAnvil_MakeTrait(level4_cont, nextLevel5);
ThorsAnvil_MakeTrait(level5, levels6);
ThorsAnvil_MakeTrait(level6_cont, nextLevel7);
ThorsAnvil_MakeTrait(level7, levels8);
ThorsAnvil_MakeTrait(level8_cont, array9);

using ThorsAnvil::Serialize::jsonExport;
using ThorsAnvil::Serialize::jsonImport;

// Use the export function to serialize
level1 levelTest = level1();
std::cout << jsonExport(levelTest) << "\n";

this gives the (stalled) output:

	{ 
		"levels2": [ 
			{ 
				"nextLevel3": 
				{ 
					"levels4": [ 
						{ 
							"nextLevel5": 
							{ 
								"levels6": [ 
									{ 
										"nextLevel7": 
										{ 
											"levels8": [ 
												{ 

moving the array9 up a level gives correct output:

class level8_cont
{
public:

};
class level7
{
public:
	level7()
	{
		levels8.emplace_back();
	}
	std::vector<level8_cont> levels8;
	std::array<int, 3> array9 = { 1, 2, 3 };
};
class level6_cont
{
public:
	level6_cont()
	{
		nextLevel7 = new level7();
	}
	level7 *nextLevel7;
};
class level5
{
public:
	level5()
	{
		levels6.emplace_back();
	}
	std::vector<level6_cont> levels6;
};
class level4_cont
{
public:
	level4_cont()
	{
		nextLevel5 = new level5();
	}
	level5 *nextLevel5;
};
class level3
{
public:
	level3()
	{
		levels4.emplace_back();
	}
	std::vector<level4_cont> levels4;
};
class level2_cont
{
public:
	level2_cont()
	{
		nextLevel3 = new level3();
	}
	level3 *nextLevel3;
};
class level1
{
public:
	level1()
	{
		levels2.emplace_back();
	}

	std::vector<level2_cont> levels2;
};

ThorsAnvil_MakeTrait(level1, levels2);
ThorsAnvil_MakeTrait(level2_cont, nextLevel3);
ThorsAnvil_MakeTrait(level3, levels4);
ThorsAnvil_MakeTrait(level4_cont, nextLevel5);
ThorsAnvil_MakeTrait(level5, levels6);
ThorsAnvil_MakeTrait(level6_cont, nextLevel7);
ThorsAnvil_MakeTrait(level7, levels8, array9);
ThorsAnvil_MakeTrait(level8_cont);

using ThorsAnvil::Serialize::jsonExport;
using ThorsAnvil::Serialize::jsonImport;

level1 levelTest = level1();
std::cout << jsonExport(levelTest) << "\n";

which gives this (correct) output:

{ 
		"levels2": [ 
			{ 
				"nextLevel3": 
				{ 
					"levels4": [ 
						{ 
							"nextLevel5": 
							{ 
								"levels6": [ 
									{ 
										"nextLevel7": 
										{ 
											"levels8": [ 
												{
												}], 
											"array9": [ 1, 2, 3]
										}
									}]
							}
						}]
				}
			}]
	}

There is no limit on the number of levels.

I built the following:

#include <ThorSerialize/SerUtil.h>
#include <ThorSerialize/JsonThor.h>

class level8_cont
{
    public:
        std::array<int, 3> array9 = { 1, 2, 3 };
};
class level7
{
    public:
        level7()
        {
            levels8.emplace_back();
        }
        std::vector<level8_cont> levels8;
};
class level6_cont
{
    public:
        level6_cont()
        {
            nextLevel7 = new level7();
        }
        level7 *nextLevel7;
};
class level5
{
    public:
        level5()
        {
            levels6.emplace_back();
        }
        std::vector<level6_cont> levels6;
};
class level4_cont
{
    public:
        level4_cont()
        {
            nextLevel5 = new level5();
        }
        level5 *nextLevel5;
};
class level3
{
    public:
        level3()
        {
            levels4.emplace_back();
        }
        std::vector<level4_cont> levels4;
};
class level2_cont
{
    public:
        level2_cont()
        {
            nextLevel3 = new level3();
        }
        level3 *nextLevel3;
};
class level1
{
    public:
        level1()
        {
            levels2.emplace_back();
        }

        std::vector<level2_cont> levels2;
};

ThorsAnvil_MakeTrait(level1, levels2);
ThorsAnvil_MakeTrait(level2_cont, nextLevel3);
ThorsAnvil_MakeTrait(level3, levels4);
ThorsAnvil_MakeTrait(level4_cont, nextLevel5);
ThorsAnvil_MakeTrait(level5, levels6);
ThorsAnvil_MakeTrait(level6_cont, nextLevel7);
ThorsAnvil_MakeTrait(level7, levels8);
ThorsAnvil_MakeTrait(level8_cont, array9);

using ThorsAnvil::Serialize::jsonExport;
using ThorsAnvil::Serialize::jsonImport;

// Use the export function to serialize
int main()
{
    level1 levelTest = level1();
    std::cout << jsonExport(levelTest) << "\n";
}

The I built and run like this:

> brew install thors-serializer
Updating Homebrew...
No stash entries found.
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> Updated Formulae
helmfile

==> Installing dependencies for thors-serializer: libyaml
==> Installing thors-serializer dependency: libyaml
==> Downloading https://homebrew.bintray.com/bottles/libyaml-0.2.4.catalina.bottle.tar.gz
######################################################################## 100.0%
==> Pouring libyaml-0.2.4.catalina.bottle.tar.gz
🍺  /usr/local/Cellar/libyaml/0.2.4: 10 files, 322.6KB
==> Installing thors-serializer
==> Downloading https://homebrew.bintray.com/bottles/thors-serializer-1.15.1.catalina.bottle.tar.gz
######################################################################## 100.0%
==> Pouring thors-serializer-1.15.1.catalina.bottle.tar.gz
🍺  /usr/local/Cellar/thors-serializer/1.15.1: 58 files, 919KB
> g++ -O3 -std=c++17 pl.cpp -lThorSerialize17
> ./a.out

	{
		"levels2": [
			{
				"nextLevel3":
				{
					"levels4": [
						{
							"nextLevel5":
							{
								"levels6": [
									{
										"nextLevel7":
										{
											"levels8": [
												{
													"array9": [ 1, 2, 3]
												}]
										}
									}]
							}
						}]
				}
			}]
	}

OK, I was able to get it working on my build. I am running from an embedded system, so I had to give it some more stack space.

Thanks!

No problem.
If I may ask are you running the version with pre-built libraries or the header only version? The header only version may result in the compiler being able to optimize out function calls (reduce stack space) at the cost of a slightly larger executable.

Please let me know how the project goes.

Loki

Currently I am using the header only version. I had to hack up a few things to get it working on ARM with arm-none-eabi. Specifically, removing the exception throwing, and setup of the config manually.

I am still in debug mode, so I haven't tried any compiler optimizations yet. I had enough RAM to increase my stack space for now.

Note: there is a header only version available for checkout.

git clone --single-branch --branch header-only https://github.com/Loki-Astari/ThorsSerializer.git

You should not need to modify the config.

Let me know if there might be something I can help fix.