Good pratice to store array in valueTree

Hi guy!

I would like your review and feeback about storing an array of bool into a valueTree. I saw some post talking about it here but I didn’t find a real solution for my need.
I would like to have an array of bool where each element would be sync with a valueTree. I’m looking for a solution that:

  • can store and restore easily the state of the array in a valueTree
  • easy to use (like accessing with array[index] = true)

Here are the solutions I found so far.

First solution:

// .h
var values;
ValueTree valueTree;

// .cpp
valueTree.setProperty(Identifier("values"), values, nullptr);

values.append(false);
values.append(false);
valueTree.setProperty(Identifier("values"), values, nullptr);

values[0] = true;
// Cannot use `valueTree.toXmlString()` because invalid XML format
for (int item : *values.getArray()) { DBG(item); }

Pro:

  • Simple to use

Con:

  • I don’t have a built in solution for undo/redo behavior of my array elements.
  • don’t get notification when a element is changed with the valueTree listener

Second solution:

// .h
// Yes, a vector of unique_ptr of cachedValue of value tree
std::vector<std::unique_ptr<CachedValue<bool>>> activations; 
ValueTree valueTree;

// .cpp
valueTree.setProperty(Identifier("values"), values, nullptr);

auto firstBool = std::make_unique<CachedValue<bool>>(valueTree.setProperty,
                                                     Identifier("_" + String(activations.size())), // "_0" underscore is used to avoid invalid XML name
                                                     nullptr,
                                                     false);
firstBool->setValue(false, nullptr);
values.push_back(std::move(firstBool));

auto secondBool = std::make_unique<CachedValue<bool>>(valueTree.setProperty,
                                                      Identifier("_" + String(activations.size())),
                                                      nullptr,
                                                      false);
secondBool->setValue(false, nullptr);
values.push_back(std::move(secondBool));

values[0]->setValue(true, nullptr);
DBG(valueTree.toXmlString());
// Print: <values _0="1" _1="0"/ >

Pro:

  • Each array element refer to the valueTree
  • Can easily convert to xml to save as a preset (?)

Con:

  • It’s kind of complexe.
  • Need to do values[0]->setValue(false, nullptr); instead of values[0] = true;

This 2 points make me think that it should be wrapped into a class to hide the logic.

Third solution:

I heard to use valueTree and add child as element. I don’t see an advantage of this but I may be wrong. Instead of an array we should then directly use a valueTree. Then to set a value we should use this:
valueTree.getChild(0).setProperty(Identifier("value"), false, nullptr); which not really user friendly. Then it should be also wrapped into a class to have a simpler interface.

What guy do you think about it? Would have a better solution?

The advantage of having a child for each bool is, you can easily listen to each bit flag individually.

If you only need to know, any of the bits have changed, I would store it as an integer in a single property, and for convenience you can put it into a BigInteger when reading, which has a nicer interface to check/set/unset individual bits. But if you like playing with shift operators and bitwise operators, you might do that manually.

Thanks you @daniel for your feedback.
I’m sorry but I don’t see the advantage of using a BigInteger here. I still have to refer each bits to the valueTree manually. Or am I missing something?

Also I tested an xml representation of having a child for each bool and it could end up to a very large file like:

<PRESETS>
  <PRESET index="0">
    <TRACKS>
     <TRACK name="track0">
       <STATES>
         <STATE id="state0" value="0"/>
         <STATE id="state1" value="1"/>
          <STATE id="state2" value="0"/>
         <STATE id="state3" value="1"/>
          <STATE id="state4" value="0"/>
        </STATES>
      </TRACK>
      <TRACK name="track1">
        <STATES>
          <STATE id="state0" value="0"/>
          <STATE id="state1" value="1"/>
          <STATE id="state2" value="0"/>
          <STATE id="state3" value="1"/>
          <STATE id="state4" value="0"/>
       </STATES>
      </TRACK>
    </TRACKS>
  </PRESET>
</PRESETS>

In my case I would have a lot of preset of at min 5 tracks where each track would have 20 states.
Would you see a more friendly- “disk saving space” architecture?
Could it be an issue?

If you are concerned about memory, don’t use XML. XML makes data user friendly, but machine unfriendly. The machine has to do expensive string comparisons, saves characters, where an index would be more appropriate.

ValueTree has a method to store in and load from a binary format, using tree.writeToStream()

By using an integer, each bool is really only one bit in size. If each of your state has 32 bool values, you end up only with 4 bytes.
If you want now to access a bit, normally you need to use bitmasks, like:

if (value & (1 << 20)) // test bit #20 

Here BigInteger comes into play:

BigInteger bits (tree.getProperty ("state"));
if (bits [20])
    // do something

bits.set (20, true);

In the XML the bitmask is then encoded as integer number (e.g. bit 9 and bit 2):

<STATE id="state" value="258"/>

Hope that helps

Yes it really helped me. Thank you.

Regarding what you said I think I will go with the following solution:

Create a wrapper class, Presets, that contain a valueTree internally and will be constructed with the main ValueTree.

Having a wrapped class will enable to use sugar syntax like presets[0] = true which internally will do bits.set(0, true);

I won’t have the behavior of a cachedValue but since it’s encapsulated I could code my own callbacks.

Thanks for you explanation the size will really decrease and I end up with:

<PRESETS>
  <PRESET index="0">
    <TRACKS>
     <TRACK name="track0" state="258"/>
     <TRACK name="track1" state="238"/>
     <TRACK name="track2" state="4"/>
     <TRACK name="track3" state="123"/>
    </TRACKS>
  </PRESET>
</PRESETS>

I even think about doing this:

<PRESETS>
  <PRESET index="0">
    <TRACKSTATES trackState0="258", trackState1="258", trackState2="258", trackState3="258"/>
  </PRESET>
</PRESETS>

Since everything is encapsulating inside a class I could access to the right value by creating the identifier on the fly
presets[index] = true
would be generated with:

const auto identifier = Identifier(trackState + String(index));
internalValueTree.setProperty(identifier, bits.toInteger(), nullptr);

Don’t know if it’s a conventional way to do it but it seems to work well.

another option:

std::bitset<numBits> bits;

and for storing:

valueTree.setProperty("bits", bits.to_string() );

and for restoring:

auto bits = std::bitset<numBits>( valueTree.getProperty("bits").to_string() );

You could also use the to_ulong() member function if you didn’t want to store it as a string in your valueTree. This approach works if you just need to use the ValueTree for (de)serializing your data to and from Disk. It’s not so good for listening to when bits change. But it’s easy enough to write a wrapper around std::bitset<> that’ll give you that ability…

https://en.cppreference.com/w/cpp/utility/bitset

1 Like