Zapamietywanie ustawień KEY/VALUE

0

Zależy mi najbardziej na wydajności zapisu i odczytu
Chciałbym aby klucz posiadał wartość domyślna
I aby można było przechowywać różne typy danych

Problem: dla każdego typu danych muszę dodać kolejny std::map
Zastanawiam się jak to zrobić lepiej ?

#include <iostream>
#include <map>

// identyfikoator + domyslna wartość 
template <typename T> 
struct ConfigKey
{
    std::string_view id;
    T def;   
    bool operator < (const ConfigKey & that) const 
    {
       return id < that.id;
    }     
};

template <typename T> 
struct ConfigKey_with_min_max
{
    std::string_view id;
    T def;   
    T _min;
    T _max;
    bool operator < (const ConfigKey_with_min_max & that) const 
    {
       return id < that.id;
    }     
};


class Config
{
private:
    std::map<ConfigKey<int>, int> configInt;    
    std::map<ConfigKey<double>, double> configDouble;    
    std::map<ConfigKey<std::string>, std::string> configString;    
    std::map<ConfigKey_with_min_max<int>, int> configInt_min_max;    
public:
    int read(ConfigKey<int> &id)
    {
        if(configInt.find(id) == configInt.end()) return id.def;
        return configInt[id];
    }   
    double read(ConfigKey<double> &id)
    {
        if(configDouble.find(id) == configDouble.end()) return id.def;
        return configDouble[id];
    }   
    std::string read(ConfigKey<std::string> &id)
    {
        if(configString.find(id) == configString.end()) return id.def;
        return configString[id];
    } 
    //
    void write(ConfigKey<int> &id, int value){configInt[id]=value;}
    void write(ConfigKey<double> &id, double value){configDouble[id]=value;}
    void write(ConfigKey<std::string> &id, std::string value){configString[id]=value;}
};

// klucze 
ConfigKey<int> CFG_INT_WIDTH{"gui.width",200};
ConfigKey<int> CFG_INT_HEIGHT{"gui.height",100};
ConfigKey<double> CFG_DOUBLE_SCALE{"gui.scale", 0.75};
ConfigKey<std::string>  CFG_STRING_CAPTION{"gui.caption","Hi Hi Hi"};

ConfigKey_with_min_max<int> CFG_INT_RANGE{"gui.range",100,10,1000};


int main(int, char**) {

    Config c;
    std::cout << "***** Default values *****\n";
    std::cout << "CFG_INT_WIDTH: " << c.read(CFG_INT_WIDTH) <<"\n";
    std::cout << "CFG_INT_HEIGHT: " << c.read(CFG_INT_HEIGHT) <<"\n";
    std::cout << "CFG_DOUBLE_SCALE: " << c.read(CFG_DOUBLE_SCALE) <<"\n";
    std::cout << "CFG_STRING_CAPTION: " << c.read(CFG_STRING_CAPTION) <<"\n";

    c.write(CFG_INT_WIDTH,333);
    c.write(CFG_INT_HEIGHT,444);
    c.write(CFG_DOUBLE_SCALE,333.33);
    c.write(CFG_STRING_CAPTION,"333.3333");

    std::cout << "***** After update value *****\n";
    std::cout << "CFG_INT_WIDTH: " << c.read(CFG_INT_WIDTH) <<"\n";
    std::cout << "CFG_INT_HEIGHT: " << c.read(CFG_INT_HEIGHT) <<"\n";
    std::cout << "CFG_DOUBLE_SCALE: " << c.read(CFG_DOUBLE_SCALE) <<"\n";
    std::cout << "CFG_STRING_CAPTION: " << c.read(CFG_STRING_CAPTION) <<"\n";
}



https://godbolt.org/z/14E3Yco6x

2

Może np. std::any? Tylko wydajnościowo to nie jest optymalne. Jak zbiór typów jest ograniczony, to być może std::variant się nada. Ale tak czy inaczej, niezbyt rozumiem w jaki sposób to jest coś co ma być wydajne - to wygląda na config po prostu.

1

std::any to overkill, ja bym użył std::variant<int, std::string, ... >.
Albo nie kombinował, ale użył po prostu jakiegoś parsera JSon-a, albo np protobuf.

0

Na tą chwilę właśnie nlohmann/json służy do przechowywania
zastanawiam się czy jak zrobię to inaczej to czy uda się coś uszczknąć z procesora.

1

W dialektach C++ - czego brakuje w standardzie - jest zwykle pra-obiekt, z którego dziedziczy OurTheBestString i inne.
To by pozwalało jakoś-tam zrobić generyczny kontener (co niewiele zmienia, bo i tak w samej aplikacji w pewnym punkcie potrzebujemy konkretnego bool'a a nie typ generyczny

Badałeś w ogóle, czy to istotny problem dla Ciebie? Znów, ciężko mi sobie wyobrazić, że dobieranie się do tych parametrów stanowi istotny overhead w programie. — enedil 2023-05-25 22:01

Popieram w 200%

1

Swoja drogą zastanawia mnie to, że to jest Config a przejmujesz się szybkością zapisu i odczytu.
Czy config będzie aż tak skomplikowany i tak duży, że to ma wpływ na szybkość aplikacji?

Ja bym zrobił tak:

namespace foo {
struct Size {
   int width = 200;
   int height = 100; 
};

struct UserIntRange {
   int start;
   int stop;
   int step;
};

struct WindowPropertyies {
    std::string caption;
    Size size = {};
    double scale = 1.0;
};
struct Config {
    WindowPropertyies mianWindow;
    UserIntRange range;
};

std::istream& readConfig(std::istream& in, Config& c);
std::ostream& writeConfig(std::ostream& out, const Config& c);
}
#include "Config.h"

#include <nlohmann/json.hpp>

namespace foo {
using json = nlohmann::json;

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Size, width, height);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(UserIntRange, start, stop, step);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(WindowPropertyies, caption, scale);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Config, mianWindow, range);

std::istream& readConfig(std::istream& in, Config& c)
{
    from_json(json::parse(in), c);
    return in;
}

std::ostream& writeConfig(std::ostream& out, const Config& c)
{
    json j;
    to_json(j, c);
    return out << std::setw(4) << j << '\n';
}
}

https://godbolt.org/z/1bnhqK6M6

Disclaimer: nlohmann/json.hpp rzuca wyjątkiem jak brakuje pola, ergo domyślne wartości nie zadziałają :(.

0
[źródło danych]  ==> [KrokA1] ==> [KrokA2]               ==>  [wizualizacja]
                 ==> [KrokB1] ==> [KrokB2]  ==> [KrokB3] ==>  
                

"źródło danych" generuje dane z częstotliwościowa max 60fps
Każdy "krok" ma parametry które finalnie trzeba wyświetlić na ekranie

Zastanawiałem się nad taką koncepcją aby razem z przetwarzanymi danymi dodać "Config" w którym wszystkie kroki zapisywały by swoje właściwości
"Wizaualizacja" dostawała by dane+config , nie potrzebował by dostępu do stanu etapów

Choć tych danych nie jest aż tak dużo 100x60fps
Może rzeczywiscie zaczne od pomiarów

0
Marius.Maximus napisał(a):

"źródło danych" generuje dane z częstotliwościowa max 60fps

A to żródło to co ? In-proicess / out-of-process, program natywny / jakiejś maszynki wirtualnej ? transmisja binarna / tekstowa ?
Tam możesz mieć 1000x więcej CPU niz w akademickim problemie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1