HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Simple C++ wrapper over libYAML

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
wrappersimpleoverlibyaml

Problem

For a personal project, I need to parse YAML file. I chose to use C-based libYAML instead of yaml-cpp, because:

  • I try to keep my dependencies to what's commonly installed and Debian statistics show 45% installs already have libYAML, vs 0.5% for yaml-cpp.



  • I don't need variant node types, as the config parser that uses this wrapper builds the final datastructures directly using a state machine.



I wrote this lightweight wrapper around the library.

The wrapper aims at encapsulating all the details of the C library, throwing exceptions when errors arise and leaking no resources in the process. In addition, its header must not have any libYAML-related stuff in it, so I can change the underlying implementation later should I want to.

Provided API is an inheritable class that converts parsing events into virtual method calls, a la hierarchical visitor pattern, but without conditional navigation.

Here comes the API (YAMLParser.h):

```
#ifndef YAML_PARSER_H
#define YAML_PARSER_H

#include
#include
#include
#include

class YAMLParser
{
public:
class ParseError : public std::exception
{
public:
ParseError(const std::string & what, size_t line, size_t col);
ParseError(const std::string & what, size_t line, size_t col,
const std::string & context, size_t ctx_line);
const char *what() const noexcept override { return m_what.c_str(); }
protected:
std::string m_what;
};

public:
virtual ~YAMLParser() {}
virtual void parse(std::istream & stream);

protected:
virtual void streamStart() = 0;
virtual void streamEnd() = 0;
virtual void documentStart() = 0;
virtual void documentEnd() = 0;
virtual void sequenceStart(const std::string & tag, const std::string & anchor) = 0;
virtual void sequenceEnd() = 0;
virtual void mappingStart(const std::string & tag, const std::string & anchor) = 0;
virtual void

Solution

Exceptions

There is no need to write your own what() method.

The class std::exception and std::runtime_error both accept a string in the constructor that defines the error message returned by what(). So there is no need to define your own version of this method:

class ParseError : public std::runtime_error
    {
        public:
            ParseError(const std::string & what, size_t line, size_t col,
                       const std::string & context = "", size_t ctx_line = -1)
                : std::runtime_error(genErrMsg(what, line, col, context, ctx_line))
            {}
        
        private:
            std::string static genErrMsg(const std::string & what, size_t line, size_t col,
                                         const std::string & context, size_t ctx_line)
            {
                std::ostringstream error;
                error << what
                      << " line " << line + 1 << " column " << col + 1
                      << " " << context;
                if (ctx_line != -1) {
                    error << " from line " << ctx_line + 1;
                }
                return error.str();
            }
    };

Code Snippets

class ParseError : public std::runtime_error
    {
        public:
            ParseError(const std::string & what, size_t line, size_t col,
                       const std::string & context = "", size_t ctx_line = -1)
                : std::runtime_error(genErrMsg(what, line, col, context, ctx_line))
            {}
        
        private:
            std::string static genErrMsg(const std::string & what, size_t line, size_t col,
                                         const std::string & context, size_t ctx_line)
            {
                std::ostringstream error;
                error << what
                      << " line " << line + 1 << " column " << col + 1
                      << " " << context;
                if (ctx_line != -1) {
                    error << " from line " << ctx_line + 1;
                }
                return error.str();
            }
    };

Context

StackExchange Code Review Q#160762, answer score: 2

Revisions (0)

No revisions yet.