2
\$\begingroup\$

My C++ code accomplishes the following:

It consists of a class called ParticleGenerator which has three important configuration options: spatialGeneratorType, angularGeneratorType and energyGeneratorType. The user would choose a value for each of these options from the possible values.

I am trying to make my code as tidy as possible and to handle as best as possible a user entering a bad value for any of these parameters. There are some setter methods to assign these values and these methods must support string arguments.

I am using a enum for each option which lists the possible values then I use a map to map a enum value to a string (human readable value).

My approach works as intended but I feel it has too much repeated code. I tried to minimize it introducing some auxiliary functions but still there are too many "if/else" statements. I tried using templates but could not make it tidier that's why I chose to use "if/else".

I have some experience writing complex code in Python but I have never written very complex projects in C++ (only scripts) I would appreciate any feedback.

Thanks.

My code:


#include <iostream>
#include <map>
#include <set>

using namespace std;
using namespace ParticleGeneratorConfig;

class ParticleGenerator {
   private:
    std::map<string, spatialGeneratorTypes> spatialGeneratorTypesMap = {
        {"OPTION1", spatialGeneratorTypes::OPTION1},
    };

    std::map<string, angularGeneratorTypes> angularGeneratorTypesMap = {
        {"OPTION1", angularGeneratorTypes::OPTION1},
    };

    map<string, energyGeneratorTypes> energyGeneratorTypesMap = {
        {"OPTION1", energyGeneratorTypes::OPTION1},
    };

    spatialGeneratorTypes spatialGeneratorType;
    angularGeneratorTypes angularGeneratorType;
    energyGeneratorTypes energyGeneratorType;

    template <class generatorTypes>
    string GeneratorEnumToString(generatorTypes type) {
        // type is in either 'spatialGeneratorTypes', 'angularGeneratorTypes' or 'energyGeneratorTypes'
        if (typeid(generatorTypes) == typeid(spatialGeneratorTypes)) {
            for (auto const& pair : spatialGeneratorTypesMap) {
                if (pair.second == spatialGeneratorType) {
                    return pair.first;
                }
            }
        } else if (typeid(generatorTypes) == typeid(angularGeneratorTypes)) {
            for (auto const& pair : angularGeneratorTypesMap) {
                if (pair.second == angularGeneratorType) {
                    return pair.first;
                }
            }
        } else if (typeid(generatorTypes) == typeid(energyGeneratorTypes)) {
            for (auto const& pair : energyGeneratorTypesMap) {
                if (pair.second == energyGeneratorType) {
                    return pair.first;
                }
            }
        } else {
            // error
            return "ERROR!";
        }
        return "NONE! (error)";
    }

    inline string NormalizeTypeString(string type) {
        std::transform(type.begin(), type.end(), type.begin(), ::tolower);
        // remove '_'
        string string_to_remove = "_";
        while (type.find(string_to_remove) != string::npos) {
            type.replace(type.find("_"), string_to_remove.length(), "");
        }
        return type;
    }

    inline void SetGeneratorTypeFromStringAndCategory(string type, string generator_category) {
        // generator_category must be one of the following: 'spatial', 'angular', 'energy'
        if (generator_category == "spatial") {
            for (auto const& pair : spatialGeneratorTypesMap) {
                if (NormalizeTypeString(pair.first) == NormalizeTypeString(type)) {
                    spatialGeneratorType = pair.second;
                    return;
                }
            }
        } else if (generator_category == "angular") {
            for (auto const& pair : angularGeneratorTypesMap) {
                if (NormalizeTypeString(pair.first) == NormalizeTypeString(type)) {
                    angularGeneratorType = pair.second;
                    return;
                }
            }
        } else if (generator_category == "energy") {
            for (auto const& pair : energyGeneratorTypesMap) {
                if (NormalizeTypeString(pair.first) == NormalizeTypeString(type)) {
                    energyGeneratorType = pair.second;
                    return;
                }
            }
        } else {
            // generator_category not valid
            cout << "ERROR: category " << generator_category << " not valid. nothing is set";
            return;
        }

        cout << "ERROR when setting " << generator_category << " generator type to: " << type << endl;
        cout << "Valid values are: ";
        string to_print = "";

        if (generator_category == "spatial") {
            for (auto const& pair : spatialGeneratorTypesMap) {
                to_print += pair.first;
                to_print += ", ";
            }
        } else if (generator_category == "angular") {
            for (auto const& pair : angularGeneratorTypesMap) {
                to_print += pair.first;
                to_print += ", ";
            }
        } else if (generator_category == "energy") {
            for (auto const& pair : energyGeneratorTypesMap) {
                to_print += pair.first;
                to_print += ", ";
            }
        }
        // remove the last ", "
        if (to_print.size() > 0) to_print.resize(to_print.size() - 2);  // '2' is the size of ", "
        cout << to_print << endl;
    }

   public:
    inline string GetSpatialGeneratorType() { return GeneratorEnumToString(spatialGeneratorType); }
    inline string GetAngularGeneratorType() { return GeneratorEnumToString(angularGeneratorType); }
    inline string GetEnergyGeneratorType() { return GeneratorEnumToString(energyGeneratorType); }

    inline void SetSpatialGeneratorType(spatialGeneratorTypes type) { spatialGeneratorType = type; }
    inline void SetSpatialGeneratorType(string type) {
        SetGeneratorTypeFromStringAndCategory(type, "spatial");
    }
    inline void SetAngularGeneratorType(angularGeneratorTypes type) { angularGeneratorType = type; }
    inline void SetAngularGeneratorType(string type) {
        SetGeneratorTypeFromStringAndCategory(type, "angular");
    }
    inline void SetEnergyGeneratorType(energyGeneratorTypes type) { energyGeneratorType = type; }
    inline void SetEnergyGeneratorType(string type) { SetGeneratorTypeFromStringAndCategory(type, "energy"); }

    ParticleGenerator();
};
```
\$\endgroup\$
  • \$\begingroup\$ We could provide much better reviews if you include some test code that showed how this class is used. \$\endgroup\$ – pacmaninbw Aug 8 at 12:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.