LCOV - code coverage report
Current view: top level - libprimis-headers - prop.h (source / functions) Coverage Total Hit
Test: Libprimis Test Coverage Lines: 91.0 % 267 243
Test Date: 2025-02-21 06:59:27 Functions: 96.0 % 50 48

            Line data    Source code
       1              : /**
       2              :  * @file prop.h
       3              :  * @brief Type-agnotic property system
       4              :  *
       5              :  * This file provides a type-agnostic property system.
       6              :  * It is used to provide a generic interface for convenient property access for objects,
       7              :  * entities and entire systems.
       8              :  */
       9              : 
      10              : #ifndef PROP_H_
      11              : #define PROP_H_
      12              : 
      13              : #include <any>
      14              : #include <variant>
      15              : 
      16              : #include "cube.h"
      17              : 
      18              : namespace prop
      19              : {
      20              : 
      21              : /**
      22              :  * @brief Storage for a property value
      23              :  *
      24              :  * This type is used to store a property value.
      25              :  * Supported types are:
      26              :  * int, float, bvec, ivec, vec, std::string
      27              :  */
      28              : typedef std::variant<int, float, bvec, ivec, vec, std::string> PropertyValue;
      29              : 
      30              : /**
      31              :  * @brief Callback type for property changes
      32              :  *
      33              :  * @param argument - The argument passed to the callback.
      34              :  */
      35              : typedef std::function<void(std::any argument)> OnChangeCallback;
      36              : 
      37              : /**
      38              :  * @brief Type of a property
      39              :  *
      40              :  * This enum is used to determine the type of a property.
      41              :  * Mandates what sort of type is stored inside the PropertyValue.
      42              :  */
      43              : enum class PropertyType
      44              : {
      45              :     NoType = -1,
      46              : 
      47              :     Int,
      48              :     Float,
      49              :     Color,
      50              :     IntVec,
      51              :     FloatVec,
      52              :     String,
      53              : 
      54              :     Count
      55              : };
      56              : 
      57              : /**
      58              :  * @brief Meta information about a property
      59              :  *
      60              :  * This class stores definition information for a property:
      61              :  * - name (string)
      62              :  * - type (PropertyType)
      63              :  * - min, default and max values (PropertyValue)
      64              :  *
      65              :  * All properties should be statically bound to their PropertyMeta counterparts.
      66              :  */
      67              : class PropertyMeta
      68              : {
      69              : private:
      70              :     std::string name;
      71              :     PropertyType type;
      72              :     PropertyValue min, def, max;
      73              :     OnChangeCallback on_change;
      74              : 
      75              : public:
      76              :     PropertyType get_type() const;
      77              :     PropertyValue get_min() const;
      78              :     PropertyValue get_def() const;
      79              :     PropertyValue get_max() const;
      80              :     std::string get_name() const;
      81              : 
      82              :     void changed(std::any argument) const;
      83              : 
      84           16 :     template<class T> PropertyMeta(std::string _name, PropertyType _type, T _min, T _def, T _max,
      85              :                                    OnChangeCallback _on_change = nullptr) :
      86           16 :         name(_name), type(_type), min(_min), def(_def), max(_max), on_change(_on_change) {}
      87            2 :     template<class T> PropertyMeta(std::string _name, PropertyType _type, T _def,
      88              :                                    OnChangeCallback _on_change = nullptr) :
      89            2 :         name(_name), type(_type), def(_def), on_change(_on_change) {}
      90              : 
      91              :     PropertyMeta(const PropertyMeta&) = delete;
      92              : };
      93              : 
      94              : /**
      95              :  * @brief A property
      96              :  *
      97              :  * @tparam PropertyMetaT - The type of the meta class, defaults to PropertyMeta
      98              :  *
      99              :  * This class is an instance of a property. It stores a value and a reference to its meta class.
     100              :  */
     101              : template<typename PropertyMetaT = PropertyMeta>
     102              : class Property
     103              : {
     104              : private:
     105              :     PropertyValue value;
     106              :     const PropertyMetaT& meta;
     107              : 
     108              :     bool set_check_type(PropertyType type) const;
     109              :     void set_clamped(PropertyValue value);
     110              : 
     111              : public:
     112              :     const PropertyValue& get_value() const;
     113              :     int get_int() const;
     114              :     float get_float() const;
     115              :     const bvec& get_color() const;
     116              :     const ivec& get_ivec() const;
     117              :     const vec& get_fvec() const;
     118              :     const std::string& get_string() const;
     119              :     size_t get_size() const;
     120              :     std::string get_name() const;
     121              :     PropertyType get_type() const;
     122              : 
     123              :     std::string to_string() const;
     124              : 
     125              :     void copy(const Property& prop);
     126              : 
     127              :     void set(PropertyValue value, std::any on_change_argument = std::any());
     128              :     void set_no_cb(PropertyValue value);
     129              : 
     130              :     void reset();
     131              : 
     132              :     void cmd_result() const;
     133              :     void cmd_result_min() const;
     134              :     void cmd_result_def() const;
     135              :     void cmd_result_max() const;
     136              : 
     137              :     virtual void pack(std::vector<uint8_t>& buf) const;
     138              :     virtual size_t unpack(const uint8_t* buf, size_t len);
     139              : 
     140              :     Property(const PropertyMetaT& _meta);
     141           19 :     virtual ~Property() = default;
     142              : };
     143              : 
     144              : 
     145              : 
     146              : ////////////////////
     147              : // Implementation //
     148              : ////////////////////
     149              : 
     150              : 
     151              : 
     152              : /**
     153              :  * @brief Get the integer value of the property
     154              :  *
     155              :  * @tparam PropertyMetaT - The type of the meta class.
     156              :  * @return int
     157              :  *
     158              :  * Caution: This function does not check the type of the property. A former check is assumed.
     159              :  */
     160              : template<typename PropertyMetaT>
     161            7 : int Property<PropertyMetaT>::get_int() const
     162              : {
     163            7 :     return std::get<int>(value);
     164              : }
     165              : 
     166              : /**
     167              :  * @brief Get the float value of the property
     168              :  *
     169              :  * @tparam PropertyMetaT - The type of the meta class.
     170              :  * @return float
     171              :  *
     172              :  * Caution: This function does not check the type of the property. A former check is assumed.
     173              :  */
     174              : template<typename PropertyMetaT>
     175            7 : float Property<PropertyMetaT>::get_float() const
     176              : {
     177            7 :     return std::get<float>(value);
     178              : }
     179              : 
     180              : /**
     181              :  * @brief Get the color value of the property
     182              :  *
     183              :  * @tparam PropertyMetaT - The type of the meta class.
     184              :  * @return bvec
     185              :  *
     186              :  * Caution: This function does not check the type of the property. A former check is assumed.
     187              :  */
     188              : template<typename PropertyMetaT>
     189            7 : const bvec& Property<PropertyMetaT>::get_color() const
     190              : {
     191            7 :     return std::get<bvec>(value);
     192              : }
     193              : 
     194              : /**
     195              :  * @brief Get the integer vector value of the property
     196              :  *
     197              :  * @tparam PropertyMetaT - The type of the meta class.
     198              :  * @return ivec
     199              :  *
     200              :  * Caution: This function does not check the type of the property. A former check is assumed.
     201              :  */
     202              : template<typename PropertyMetaT>
     203            8 : const ivec& Property<PropertyMetaT>::get_ivec() const
     204              : {
     205            8 :     return std::get<ivec>(value);
     206              : }
     207              : 
     208              : /**
     209              :  * @brief Get the float vector value of the property
     210              :  *
     211              :  * @tparam PropertyMetaT - The type of the meta class.
     212              :  * @return vec
     213              :  *
     214              :  * Caution: This function does not check the type of the property. A former check is assumed.
     215              :  */
     216              : template<typename PropertyMetaT>
     217            8 : const vec& Property<PropertyMetaT>::get_fvec() const
     218              : {
     219            8 :     return std::get<vec>(value);
     220              : }
     221              : 
     222              : /**
     223              :  * @brief Get the string value of the property
     224              :  *
     225              :  * @tparam PropertyMetaT - The type of the meta class.
     226              :  * @return std::string
     227              :  *
     228              :  * Caution: This function does not check the type of the property. A former check is assumed.
     229              :  */
     230              : template<typename PropertyMetaT>
     231            6 : const std::string& Property<PropertyMetaT>::get_string() const
     232              : {
     233            6 :     return std::get<std::string>(value);
     234              : }
     235              : 
     236              : /**
     237              :  * @brief Get the size of the property
     238              :  *
     239              :  * @tparam PropertyMetaT - The type of the meta class.
     240              :  * @return size_t
     241              :  *
     242              :  * Returns the size of the stored value in bytes.
     243              :  */
     244              : template<typename PropertyMetaT>
     245           24 : size_t Property<PropertyMetaT>::get_size() const
     246              : {
     247           24 :     switch(get_type())
     248              :     {
     249            5 :     case PropertyType::Int:
     250            5 :         return sizeof(int);
     251            5 :     case PropertyType::Float:
     252            5 :         return sizeof(float);
     253            5 :     case PropertyType::Color:
     254            5 :         return sizeof(bvec);
     255            4 :     case PropertyType::IntVec:
     256            4 :         return sizeof(ivec);
     257            4 :     case PropertyType::FloatVec:
     258            4 :         return sizeof(vec);
     259            1 :     case PropertyType::String:
     260            1 :         return get_string().size();
     261            0 :     default:
     262            0 :         return 0;
     263              :     }
     264              : }
     265              : 
     266              : template<typename PropertyMetaT>
     267            6 : std::string Property<PropertyMetaT>::to_string() const
     268              : {
     269            6 :     switch(get_type())
     270              :     {
     271            1 :     case PropertyType::Int:
     272            1 :         return std::to_string(get_int());
     273              : 
     274            1 :     case PropertyType::Float:
     275            1 :         return std::to_string(get_float());
     276              : 
     277            1 :     case PropertyType::Color:
     278            1 :         return std::to_string(get_color().r()) + " " + std::to_string(get_color().g()) + " " + std::to_string(get_color().b());
     279              : 
     280            1 :     case PropertyType::IntVec:
     281            1 :         return std::to_string(get_ivec().x) + " " + std::to_string(get_ivec().y) + " " + std::to_string(get_ivec().z);
     282              : 
     283            1 :     case PropertyType::FloatVec:
     284            1 :         return std::to_string(get_fvec().x) + " " + std::to_string(get_fvec().y) + " " + std::to_string(get_fvec().z);
     285              : 
     286            1 :     case PropertyType::String:
     287            1 :         return get_string();
     288              : 
     289            0 :     default:
     290            0 :         return "";
     291              :     }
     292              : }
     293              : 
     294              : template<typename PropertyMetaT>
     295           31 : bool Property<PropertyMetaT>::set_check_type(PropertyType type) const
     296              : {
     297              :     // typename used in debug printout below
     298              :     //static constexpr std::string_view typenames[] =
     299              :     //{
     300              :     //    "int", "float", "color", "int vector", "float vector", "string"
     301              :     //};
     302              : 
     303           31 :     if(get_type() != type)
     304              :     {
     305              :         // conoutf("Error: %s, incorrect property assignment type: got %s, expected %s",
     306              :         //         meta.get_name().c_str(), std::string(typenames[static_cast<size_t>(type)]).c_str(),
     307              :         //         std::string(typenames[static_cast<size_t>(get_type())]).c_str());
     308              : 
     309            0 :         return false;
     310              :     }
     311              : 
     312           31 :     return true;
     313              : }
     314              : 
     315              : /**
     316              :  * @brief Get the name of the property
     317              :  *
     318              :  * @tparam PropertyMetaT - The type of the meta class.
     319              :  * @return std::string
     320              :  *
     321              :  * Returns the name of the property, as per the definition in the meta class.
     322              :  */
     323              : template<typename PropertyMetaT>
     324          227 : std::string Property<PropertyMetaT>::get_name() const
     325              : {
     326          227 :     return meta.get_name();
     327              : }
     328              : 
     329              : /**
     330              :  * @brief Get the type of the property
     331              :  *
     332              :  * @tparam PropertyMetaT - The type of the meta class.
     333              :  * @return std::string
     334              :  *
     335              :  * Returns the type of the property, as per the definition in the meta class.
     336              :  */
     337              : template<typename PropertyMetaT>
     338          116 : PropertyType Property<PropertyMetaT>::get_type() const
     339              : {
     340          116 :     return meta.get_type();
     341              : }
     342              : 
     343              : /**
     344              :  * @brief Copy the value of another property, will not invoke callback
     345              :  *
     346              :  * @tparam PropertyMetaT - The type of the meta class.
     347              :  * @param prop - The property to copy the value from.
     348              :  * @param on_change_arg - Optional argument for on_change callback.
     349              :  *
     350              :  * Note: type check is performed automatically, value of an incompatible type is ignored and reported.
     351              :  * Value is clamped to the range defined in the meta class, if applicable.
     352              :  */
     353              : template<typename PropertyMetaT>
     354              : void Property<PropertyMetaT>::copy(const Property& prop)
     355              : {
     356              :     set_no_cb(prop.value);
     357              : }
     358              : 
     359              : template<typename PropertyMetaT>
     360           31 : void Property<PropertyMetaT>::set_clamped(PropertyValue value)
     361              : {
     362           31 :     switch(get_type())
     363              :     {
     364            7 :         case PropertyType::Int:
     365              :         {
     366            7 :             int v = std::get<int>(value);
     367            7 :             this->value = std::clamp(v, std::get<int>(meta.get_min()), std::get<int>(meta.get_max()));
     368            7 :             break;
     369              :         }
     370              : 
     371            6 :         case PropertyType::Float:
     372              :         {
     373            6 :             float v = std::get<float>(value);
     374            6 :             this->value = std::clamp(v, std::get<float>(meta.get_min()), std::get<float>(meta.get_max()));
     375            6 :             break;
     376              :         }
     377              : 
     378            5 :         case PropertyType::IntVec:
     379              :         {
     380            5 :             ivec v = std::get<ivec>(value);
     381           10 :             this->value = ivec(v).min(std::get<ivec>(meta.get_max()))
     382           10 :                                  .max(std::get<ivec>(meta.get_min()));
     383            5 :             break;
     384              :         }
     385              : 
     386            5 :         case PropertyType::FloatVec:
     387              :         {
     388            5 :             vec v = std::get<vec>(value);
     389           10 :             this->value = vec(v).min(std::get<vec>(meta.get_max()))
     390           10 :                                 .max(std::get<vec>(meta.get_min()));
     391            5 :             break;
     392              :         }
     393              : 
     394            8 :         default:
     395            8 :             this->value = value;
     396            8 :             break;
     397              :     }
     398           31 : }
     399              : 
     400              : /**
     401              :  * @brief Set the value of the property
     402              :  *
     403              :  * @tparam PropertyMetaT - The type of the meta class.
     404              :  * @param value - The new value of the property.
     405              :  * @param on_change_arg - Optional argument for on_change callback.
     406              :  *
     407              :  * Note: type check is performed automatically, value of an incompatible type is ignored and reported.
     408              :  * Value is clamped to the range defined in the meta class, if applicable.
     409              :  */
     410              : template<typename PropertyMetaT>
     411           31 : void Property<PropertyMetaT>::set(PropertyValue value, std::any on_change_arg)
     412              : {
     413           31 :     if(set_check_type(static_cast<PropertyType>(value.index())))
     414              :     {
     415           31 :         set_clamped(value);
     416           31 :         meta.changed(on_change_arg);
     417              :     }
     418           31 : }
     419              : 
     420              : /**
     421              :  * @brief Set the value of the property without invoking callback
     422              :  *
     423              :  * @tparam PropertyMetaT - The type of the meta class.
     424              :  * @param value - The new value of the property.
     425              :  *
     426              :  * Note: type check is performed automatically, value of an incompatible type is ignored and reported.
     427              :  * Value is clamped to the range defined in the meta class, if applicable.
     428              :  */
     429              : template<typename PropertyMetaT>
     430            0 : void Property<PropertyMetaT>::set_no_cb(PropertyValue value)
     431              : {
     432            0 :     if(set_check_type(static_cast<PropertyType>(value.index())))
     433              :     {
     434            0 :         set_clamped(value);
     435              :     }
     436            0 : }
     437              : 
     438              : /**
     439              :  * @brief Reset the value of the property to the default value
     440              :  *
     441              :  * @tparam PropertyMetaT - The type of the meta class.
     442              :  */
     443              : template<typename PropertyMetaT>
     444           30 : void Property<PropertyMetaT>::reset()
     445              : {
     446           30 :     this->value = meta.get_def();
     447           30 : }
     448              : 
     449            6 : static void _prop_cmd_result_value(PropertyValue value, PropertyType type)
     450              : {
     451            6 :     switch(type)
     452              :     {
     453            1 :         case PropertyType::Int:
     454            1 :             intret(std::get<int>(value));
     455            1 :             break;
     456              : 
     457            1 :         case PropertyType::Float:
     458            1 :             floatret(std::get<float>(value));
     459            1 :             break;
     460              : 
     461            1 :         case PropertyType::Color:
     462            1 :             intret(std::get<bvec>(value).tohexcolor());
     463            1 :             break;
     464              : 
     465            1 :         case PropertyType::IntVec:
     466              :         {
     467            1 :             const ivec& v = std::get<ivec>(value);
     468            1 :             result(tempformatstring("%d %d %d", v.x, v.y, v.z));
     469            1 :             break;
     470              :         }
     471              : 
     472            1 :         case PropertyType::FloatVec:
     473              :         {
     474            1 :             const vec& v = std::get<vec>(value);
     475            1 :             result(tempformatstring("%f %f %f", v.x, v.y, v.z));
     476            1 :             break;
     477              :         }
     478              : 
     479            1 :         case PropertyType::String:
     480            1 :             result(std::get<std::string>(value).c_str());
     481            1 :             break;
     482              : 
     483            0 :         default: break;
     484              :     }
     485            6 : }
     486              : 
     487              : /**
     488              :  * @brief Results the value of the property
     489              :  *
     490              :  * @tparam PropertyMetaT - The type of the meta class.
     491              :  */
     492              : template<typename PropertyMetaT>
     493            6 : void Property<PropertyMetaT>::cmd_result() const
     494              : {
     495            6 :     _prop_cmd_result_value(value, get_type());
     496            6 : }
     497              : 
     498              : /**
     499              :  * @brief Results the minimum value of the property
     500              :  *
     501              :  * @tparam PropertyMetaT - The type of the meta class.
     502              :  */
     503              : template<typename PropertyMetaT>
     504              : void Property<PropertyMetaT>::cmd_result_min() const
     505              : {
     506              :     _prop_cmd_result_value(meta.get_min(), get_type());
     507              : }
     508              : 
     509              : /**
     510              :  * @brief Results the default value of the property
     511              :  *
     512              :  * @tparam PropertyMetaT - The type of the meta class.
     513              :  */
     514              : template<typename PropertyMetaT>
     515              : void Property<PropertyMetaT>::cmd_result_def() const
     516              : {
     517              :     _prop_cmd_result_value(meta.get_def(), get_type());
     518              : }
     519              : 
     520              : /**
     521              :  * @brief Results the maximum value of the property
     522              :  *
     523              :  * @tparam PropertyMetaT - The type of the meta class.
     524              :  */
     525              : template<typename PropertyMetaT>
     526              : void Property<PropertyMetaT>::cmd_result_max() const
     527              : {
     528              :     _prop_cmd_result_value(meta.get_max(), get_type());
     529              : }
     530              : 
     531              : /**
     532              :  * @brief Packs the property into a buffer
     533              :  *
     534              :  * @tparam PropertyMetaT - The type of the meta class.
     535              :  * @param buf - The buffer to pack the property into.
     536              :  */
     537              : template<typename PropertyMetaT>
     538            6 : void Property<PropertyMetaT>::pack(std::vector<uint8_t>& buf) const
     539              : {
     540            6 :     size_t data_size = get_size();
     541              : 
     542            6 :     vectorput(buf, data_size);
     543              : 
     544            6 :     switch(get_type())
     545              :     {
     546            1 :         case PropertyType::Int:
     547              :         {
     548            1 :             vectorput(buf, get_int());
     549            1 :             break;
     550              :         }
     551              : 
     552            1 :         case PropertyType::Float:
     553              :         {
     554            1 :             vectorput(buf, get_float());
     555            1 :             break;
     556              :         }
     557              : 
     558            1 :         case PropertyType::Color:
     559              :         {
     560            1 :             vectorput(buf, get_color());
     561            1 :             break;
     562              :         }
     563              : 
     564            1 :         case PropertyType::IntVec:
     565              :         {
     566            1 :             vectorput(buf, get_ivec());
     567            1 :             break;
     568              :         }
     569              : 
     570            1 :         case PropertyType::FloatVec:
     571              :         {
     572            1 :             vectorput(buf, get_fvec());
     573            1 :             break;
     574              :         }
     575              : 
     576            1 :         case PropertyType::String:
     577              :         {
     578            1 :             std::string data = get_string();
     579              :             // Null-terminator not needed, since we know the size
     580            1 :             vectorput(buf, reinterpret_cast<const uint8_t*>(data.data()), data.size());
     581            1 :             break;
     582            1 :         }
     583              : 
     584            0 :         default: break;
     585              :     }
     586            6 : }
     587              : 
     588              : /**
     589              :  * @brief Unpacks the property from a buffer
     590              :  *
     591              :  * @tparam PropertyMetaT - The type of the meta class.
     592              :  * @param buf - The buffer to unpack the property from.
     593              :  * @param buf_size - The size of the buffer.
     594              :  *
     595              :  * @return The number of bytes read from the buffer.
     596              :  */
     597              : template<typename PropertyMetaT>
     598            6 : size_t Property<PropertyMetaT>::unpack(const uint8_t* buf, size_t buf_size)
     599              : {
     600            6 :     size_t buf_read = 0;
     601            6 :     const size_t* data_size_packed = nullptr;
     602              : 
     603            6 :     if(buf_size <= sizeof(*data_size_packed))
     604              :     {
     605              :         // conoutf("Error unpacking prop '%s': not enough data to get the size!", meta.get_name().c_str());
     606            0 :         return 0;
     607              :     }
     608              : 
     609            6 :     data_size_packed = reinterpret_cast<const size_t*>(buf);
     610              : 
     611            6 :     buf_read += sizeof(*data_size_packed);
     612              : 
     613            6 :     static auto size_check = [&](size_t needed_size)
     614              :     {
     615            6 :         if(buf_size - buf_read < needed_size)
     616              :         {
     617              :             // conoutf("Error unpacking prop '%s': not enough data!", meta.get_name().c_str());
     618            0 :             return false;
     619              :         }
     620              : 
     621            6 :         return true;
     622              :     };
     623              : 
     624            6 :     switch(get_type())
     625              :     {
     626            3 :         case PropertyType::Int:
     627              :         case PropertyType::Color:
     628              :         case PropertyType::Float:
     629            3 :             if(*data_size_packed != get_size())
     630              :             {
     631              :                 // conoutf("Error unpacking prop '%s': unexpected data size! Wanted: %lu, got: %lu",
     632              :                 //         meta.get_name().c_str(), get_size(), *data_size_packed);
     633              : 
     634            0 :                 return 0;
     635              :             }
     636            3 :             break;
     637              : 
     638            3 :         default: break;
     639              :     }
     640              : 
     641            6 :     switch(get_type())
     642              :     {
     643            1 :         case PropertyType::Int:
     644              :         {
     645            1 :             if(!size_check(get_size()))
     646              :             {
     647            0 :                 return 0;
     648              :             }
     649              : 
     650              :             int ival;
     651            1 :             memcpy(&ival, buf + buf_read, get_size());
     652            1 :             buf_read += get_size();
     653            1 :             value = ival;
     654            1 :             break;
     655              :         }
     656              : 
     657            1 :         case PropertyType::Float:
     658              :         {
     659            1 :             if(!size_check(get_size()))
     660              :             {
     661            0 :                 return 0;
     662              :             }
     663              : 
     664              :             float fval;
     665            1 :             memcpy(&fval, buf + buf_read, get_size());
     666            1 :             buf_read += get_size();
     667            1 :             value = fval;
     668            1 :             break;
     669              :         }
     670              : 
     671            1 :         case PropertyType::Color:
     672              :         {
     673            1 :             if(!size_check(get_size()))
     674              :             {
     675            0 :                 return 0;
     676              :             }
     677              : 
     678            1 :             bvec cval;
     679            1 :             memcpy(&cval, buf + buf_read, get_size());
     680            1 :             buf_read += get_size();
     681            1 :             value = cval;
     682            1 :             break;
     683              :         }
     684              : 
     685            1 :         case PropertyType::IntVec:
     686              :         {
     687            1 :             if(!size_check(get_size()))
     688              :             {
     689            0 :                 return 0;
     690              :             }
     691              : 
     692            1 :             ivec ivecval;
     693            1 :             memcpy(&ivecval, buf + buf_read, get_size());
     694            1 :             buf_read += get_size();
     695            1 :             value = ivecval;
     696            1 :             break;
     697              :         }
     698              : 
     699            1 :         case PropertyType::FloatVec:
     700              :         {
     701            1 :             if(!size_check(get_size()))
     702              :             {
     703            0 :                 return 0;
     704              :             }
     705              : 
     706            1 :             vec vecval;
     707            1 :             memcpy(&vecval, buf + buf_read, get_size());
     708            1 :             buf_read += get_size();
     709            1 :             value = vecval;
     710            1 :             break;
     711              :         }
     712              : 
     713            1 :         case PropertyType::String:
     714              :         {
     715            1 :             if(!size_check(*data_size_packed))
     716              :             {
     717            0 :                 return 0;
     718              :             }
     719              : 
     720            1 :             std::string sval(reinterpret_cast<const char*>(buf + buf_read), *data_size_packed);
     721            1 :             buf_read += *data_size_packed;
     722            1 :             value = sval;
     723            1 :             break;
     724            1 :         }
     725              : 
     726            0 :         default: break;
     727              :     }
     728              : 
     729            6 :     return buf_read;
     730              : }
     731              : 
     732              : /**
     733              :  * @brief Creates a new property with the given meta class.
     734              :  *
     735              :  * @tparam PropertyMetaT - The type of the meta class.
     736              :  * @param _meta - The meta class.
     737              :  */
     738              : template<typename PropertyMetaT>
     739           30 : Property<PropertyMetaT>::Property(const PropertyMetaT& _meta) : meta(_meta)
     740              : {
     741           30 :     reset();
     742           30 : }
     743              : 
     744              : /**
     745              :  * @brief Gets the type of the property definition.
     746              :  *
     747              :  * @return PropertyType
     748              :  */
     749          116 : PropertyType PropertyMeta::get_type() const
     750              : {
     751          116 :     return type;
     752              : }
     753              : 
     754              : /**
     755              :  * @brief Gets the minimum value of the property definition.
     756              :  *
     757              :  * @return PropertyValue
     758              :  */
     759           23 : PropertyValue PropertyMeta::get_min() const
     760              : {
     761           23 :     return min;
     762              : }
     763              : 
     764              : /**
     765              :  * @brief Gets the default value of the property definition.
     766              :  *
     767              :  * @return PropertyValue
     768              :  */
     769           30 : PropertyValue PropertyMeta::get_def() const
     770              : {
     771           30 :     return def;
     772              : }
     773              : 
     774              : /**
     775              :  * @brief Gets the maximum value of the property definition.
     776              :  *
     777              :  * @return PropertyValue
     778              :  */
     779           23 : PropertyValue PropertyMeta::get_max() const
     780              : {
     781           23 :     return max;
     782              : }
     783              : 
     784              : /**
     785              :  * @brief Gets the name of the property definition.
     786              :  *
     787              :  * @return std::string
     788              :  */
     789          299 : std::string PropertyMeta::get_name() const
     790              : {
     791          299 :     return name;
     792              : }
     793              : 
     794           31 : void PropertyMeta::changed(std::any argument) const
     795              : {
     796           31 :     if(on_change)
     797              :     {
     798            1 :         on_change(argument);
     799              :     }
     800           31 : }
     801              : 
     802              : 
     803              : 
     804              : //////////////////////
     805              : // Helper functions //
     806              : //////////////////////
     807              : 
     808              : 
     809              : 
     810              : /**
     811              :  * @brief Finds a property with the given name in the given array.
     812              :  *
     813              :  * @tparam PropertyT - Property class type
     814              :  * @tparam N - Size of the array
     815              :  * @param name - The name of the property to find.
     816              :  * @param props - The array of properties to search.
     817              :  * @return PropertyT* - The property if found, nullptr otherwise.
     818              :  */
     819              : template<typename PropertyT, std::size_t N>
     820           62 : PropertyT* find_prop(std::string name, std::array<PropertyT, N>& props)
     821              : {
     822          217 :     for(PropertyT& prop : props)
     823              :     {
     824          216 :         if(prop.get_name() == name)
     825              :         {
     826           61 :             return &prop;
     827              :         }
     828              :     }
     829              : 
     830            1 :     return nullptr;
     831              : }
     832              : 
     833              : /**
     834              :  * @brief Finds a property with the given name in the given array.
     835              :  *
     836              :  * @tparam PropertyT - Property class type
     837              :  * @tparam N - Size of the array
     838              :  * @param name - The name of the property to find.
     839              :  * @param props - The array of properties to search.
     840              :  * @return PropertyT* - The property if found, nullptr otherwise.
     841              :  */
     842              : template<typename PropertyT, std::size_t N>
     843            1 : const PropertyT* find_prop(std::string name, const std::array<PropertyT, N>& props)
     844              : {
     845           12 :     for(const PropertyT& prop : props)
     846              :     {
     847           11 :         if(prop.get_name() == name)
     848              :         {
     849            0 :             return &prop;
     850              :         }
     851              :     }
     852              : 
     853            1 :     return nullptr;
     854              : }
     855              : 
     856              : /**
     857              :  * @brief Sets the value of a property with the given name in the given array.
     858              :  *
     859              :  * @tparam PropertyT - Property class type
     860              :  * @tparam N - Size of the array
     861              :  * @param name - The name of the property to set.
     862              :  * @param value - The value to set the property to. Value is clamped to the property's min/max values, if applicable.
     863              :  * @param props - The array of properties to search.
     864              :  * @param on_change_arg - Optional argument to pass to the property's on_change callback.
     865              :  * @return true - The property was found and set.
     866              :  */
     867              : template<typename PropertyT, std::size_t N>
     868           32 : bool set_prop(std::string name, PropertyValue value, std::array<PropertyT, N>& props,
     869              :               std::any on_change_arg = std::any())
     870              : {
     871           32 :     PropertyT* prop = find_prop(name, props);
     872           32 :     if(!prop)
     873              :     {
     874              :         // conoutf("Property %s not found!", name.c_str());
     875            1 :         return false;
     876              :     }
     877              : 
     878           31 :     prop->set(value, on_change_arg);
     879           31 :     return true;
     880              : }
     881              : 
     882              : /**
     883              :  * @brief Finds a property definition with the given name in the given array.
     884              :  *
     885              :  * @tparam PropertyMetaT - PropertyMeta class type
     886              :  * @tparam N - Size of the array
     887              :  * @param name - The name of the property definition to find.
     888              :  * @param prop_metas - The array of property definitions to search.
     889              :  * @return const PropertyMetaT* - The property definition if found, nullptr otherwise.
     890              :  */
     891              : template<typename PropertyMetaT, std::size_t N>
     892              : const PropertyMetaT* find_prop_meta(std::string name, const std::array<PropertyMetaT, N>& prop_metas)
     893              : {
     894              :     for(const PropertyMetaT& prop_meta : prop_metas)
     895              :     {
     896              :         if(prop_meta.get_name() == name)
     897              :         {
     898              :             return &prop_meta;
     899              :         }
     900              :     }
     901              : 
     902              :     return nullptr;
     903              : }
     904              : 
     905              : /**
     906              :  * @brief Packs the given properties into the given buffer.
     907              :  *
     908              :  * @tparam PropertyT - Property class type
     909              :  * @tparam N - Size of the array
     910              :  * @param props - The array of properties to pack.
     911              :  * @param buf - The buffer to pack the properties into.
     912              :  */
     913              : template<typename PropertyT, std::size_t N>
     914            1 : void pack_props(const std::array<PropertyT, N>& props, std::vector<uint8_t>& buf)
     915              : {
     916            7 :     for(const PropertyT& prop : props)
     917              :     {
     918            6 :         prop.pack(buf);
     919              :     }
     920            1 : }
     921              : 
     922              : /**
     923              :  * @brief Unpacks the given buffer into the given properties.
     924              :  *
     925              :  * @tparam PropertyT - Property class type
     926              :  * @tparam N - Size of the array
     927              :  * @param buf - The buffer to unpack.
     928              :  * @param props - The array of properties to unpack into.
     929              :  * @return size_t - The number of properties unpacked.
     930              :  */
     931              : template<typename PropertyT, std::size_t N>
     932            1 : size_t unpack_props(const std::vector<uint8_t>& buf, std::array<PropertyT, N>& props)
     933              : {
     934            1 :     size_t prop_idx = 0;
     935            1 :     size_t read_pos = 0;
     936              : 
     937            7 :     while(read_pos < buf.size())
     938              :     {
     939            6 :         if(prop_idx >= N)
     940              :         {
     941            0 :             break;
     942              :         }
     943              : 
     944            6 :         PropertyT &prop = props[prop_idx];
     945              : 
     946            6 :         int unpacked_size = prop.unpack(buf.data() + read_pos, buf.size() - read_pos);
     947            6 :         if(!unpacked_size)
     948              :         {
     949            0 :             break;
     950              :         }
     951              : 
     952            6 :         read_pos += unpacked_size;
     953            6 :         prop_idx++;
     954              :     }
     955              : 
     956            1 :     return prop_idx;
     957              : }
     958              : 
     959              : template<std::size_t N, typename PropertyT, std::size_t... Is, typename PropertyMetaT>
     960            5 : std::array<PropertyT, N> _make_props_array_impl(std::index_sequence<Is...>,
     961              :                                                const PropertyMetaT (&prop_meta)[N])
     962              : {
     963            5 :     return { PropertyT(prop_meta[Is])... };
     964            5 : }
     965              : 
     966              : /**
     967              :  * @brief Creates an array of properties from the given property definitions.
     968              :  *
     969              :  * @tparam N - Size of the array
     970              :  * @tparam PropertyT - Property class type
     971              :  * @tparam Is - Index sequence
     972              :  * @tparam PropertyMetaT - PropertyMeta class type
     973              :  * @param prop_meta - The array of property definitions to create properties from.
     974              :  * @return std::array<PropertyT, N> - The array of properties bound to meta information.
     975              :  */
     976              : template<std::size_t N, typename PropertyT, std::size_t... Is, typename PropertyMetaT>
     977            5 : std::array<PropertyT, N> make_props_array(const PropertyMetaT (&prop_meta)[N])
     978              : {
     979            5 :     return _make_props_array_impl<N, PropertyT>(std::make_index_sequence<N>{}, prop_meta);
     980              : }
     981              : 
     982              : }; // namespace prop
     983              : 
     984              : #endif // PROP_H_
        

Generated by: LCOV version 2.0-1