Boost:PropertyTree:Example

Boost:PropertyTree를 사용하는 샘플 코드.

/**
 * @file   Property.hpp
 * @brief  Property class prototype.
 * @author username
 * @date   2015-04-03
 * @date   2015-06-13 (Create Xml, Ini, Json Property)
 * @date   2015-08-22 (Move the world library)
 */

#ifndef __INCLUDE_WORLD__WORLD_PROPERTY_PROPERTY_HPP__
#define __INCLUDE_WORLD__WORLD_PROPERTY_PROPERTY_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <string>

#if defined(__GNUC__) && defined(__cplusplus)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Winline"
#endif

#include <boost/property_tree/ptree.hpp>

#if defined(__GNUC__) && defined(__cplusplus)
# pragma GCC diagnostic pop
#endif

#include <boost/filesystem.hpp>

/**
 * Create a property accessor & mutator macro.
 */
#define CREATE_PROPERTY(type, section, name, default_value, ptree) \
    public: \
        type get_##section##_##name() const \
        { \
            return ptree.get<type>(#section "." #name, default_value); \
        } \
    public: \
        void put_##section##_##name(type const & value = default_value) \
        { \
            ptree.put(#section "." #name, value); \
        }

#define CREATE_PROPERTY2(type, section, name, default_value) \
    CREATE_PROPERTY(type, section, name, default_value, _ptree)

// --------------
namespace world {
// --------------

/**
 * Basic property class.
 *
 * @author username
 * @date   2015-04-03
 * @date   2015-08-22 (Move the world library)
 */
class Property : public Noncopyable
{
protected:
    std::string _path;
    boost::property_tree::ptree _ptree;

public:
    Property() = default;
    virtual ~Property() = default;

    Property(std::string const & path) : _path(path) {
        // EMPTY.
    }

public:
    Property(std::string const & path);

public:
    /** if not exist put the default and save. */
    void loadOrDefaultSave() {
        if (exists()) {
            load();
        } else {
            putDefault();
            save();
        }
    }

public:
    inline void setPath(std::string const & path)
    {   this->_path = path;     }
    inline std::string getPath() const
    {   return this->_path;     }
    boost::property_tree::ptree & getPtree()
    {   return this->_ptree;    }

// File system.
public:
    /** Check the property file exists. */
    bool exists() const {
        return boost::filesystem::exists(boost::filesystem::path(_path));
    }

    /** Remove property file. */
    bool remove() const {
        return boost::filesystem::remove(boost::filesystem::path(_path));
    }

public:
    virtual void putDefault() {
        // EMPTY.
    }

// save & load.
public:
    virtual bool load() = 0;
    virtual bool save() = 0;
};

// -----------------
} // namespace world
// -----------------


#if defined(WORLD_COMP_GNUC) && defined(WORLD_LANG_STDCPP)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Winline"
# pragma GCC diagnostic ignored "-Wreturn-type"
# if !defined(WORLD_COMP_LLVM)
#  pragma GCC diagnostic ignored "-Wunused-local-typedefs"
# endif
#endif

#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/json_parser.hpp>

#if defined(WORLD_COMP_GNUC) && defined(WORLD_LANG_STDCPP)
# pragma GCC diagnostic pop
#endif


#define __PROPERTY_CLASS(classname, parsername, reader, writer, error) \
    class classname : public Property \
    { \
    public: \
        classname() : Property() { } \
        classname(std::string const & path) : Property(path) { } \
        virtual ~classname() { } \
    public: \
        bool load() override \
        { \
            try { \
                boost::property_tree::parsername::reader(_path, _ptree); \
            } catch (boost::property_tree::error & e) { \
                return false; \
            } \
            return true; \
        } \
    public: \
        bool save() override \
        { \
            try { \
                boost::property_tree::parsername::writer(_path, _ptree); \
            } catch (boost::property_tree::error & e) { \
                return false; \
            } \
            return true; \
        } \
    };

#define __PROPERTY_CLASS2(type) \
        __PROPERTY_CLASS(type##Property, type##_parser, read_##type, write_##type, type##_parser_error)

// --------------
namespace world {
// --------------

__PROPERTY_CLASS2(ini);
__PROPERTY_CLASS2(xml);
__PROPERTY_CLASS2(json);

/**
 * @defgroup __DOXYGEN_GROUP__PROPERTY_LIST__ Property list
 * @brief List of Property class.
 * @{
 */

using  IniProperty =  iniProperty;
using  XmlProperty =  xmlProperty;
using JsonProperty = jsonProperty;

/**
 * @}
 */

// -----------------
} // namespace world
// -----------------

#endif // __INCLUDE_WORLD__WORLD_PROPERTY_PROPERTY_HPP__

사용 방법은 아래와 같다.

using namespace world;

static char const * TEST_INI_FILE_PATH   = "world.test.ini";
static char const * DEFAULT_TEST_STRING  = "DEFAULT_STRING";
static int  const   DEFAULT_TEST_INTEGER = 60;

class PropertyTest : public IniProperty
{
private:
    std::string TEST_STRING;

public:
    PropertyTest() : IniProperty(TEST_INI_FILE_PATH)
    {
        TEST_STRING = "TestString";
    }
    virtual ~PropertyTest()
    {
        __EMPTY_BLOCK__
    }

public:
    virtual void putDefault() override
    {
        put_test_string();
        put_test_integer();
    }

public:
    CREATE_PROPERTY2(std::string, test, string, DEFAULT_TEST_STRING);
    CREATE_PROPERTY2(int, test, integer, DEFAULT_TEST_INTEGER);
};

int main()
{
    if (this->exists() == true) {
        this->remove();
    }
    assert(this->exists() == false);
    assert(this->load() == false);

    this->loadOrDefaultSave();

    assert(this->get_test_string() == std::string(DEFAULT_TEST_STRING));
    assert(this->get_test_integer() == std::string(DEFAULT_TEST_INTEGER));

    assert(this->exists());
    assert(this->remove());
    return 0;
}