denny 2025. 5. 26. 11:34
  • 빠르고 가벼운 JSON 파서: RapidJSON
  • JSON Schema 기반 C++ 코드 자동 생성: Python + Jinja2

으로 전체 구조와 예제를 제공하겠습니다.


✅ 목표

  • RapidJSON만 사용하여 가볍고 빠른 JSON 파싱
  • JSON Schema 기반 Python 코드 생성기로 C++ 구조체 자동 생성
  • from_json() / to_json() 대신 RapidJSON의 DOM API 사용

🧩 1. JSON Schema 예시

📁 schema/character.schema.json

{
  "title": "Character",
  "type": "object",
  "properties": {
    "id": { "type": "integer" },
    "name": { "type": "string" },
    "hp": { "type": "integer" },
    "class": {
      "type": "string",
      "enum": ["Warrior", "Mage", "Archer"]
    }
  },
  "required": ["id", "name", "hp", "class"]
}

🛠️ 2. Python + Jinja2: 구조체 생성기

📁 template/class.hpp.jinja2

#pragma once
#include <string>
#include <rapidjson/document.h>

enum class {{ enum_name }} {
    {% for val in enum_values %}
    {{ val }}{{ "," if not loop.last }}
    {% endfor %}
};

struct {{ struct_name }} {
    int id;
    std::string name;
    int hp;
    {{ enum_name }} class_type;

    // RapidJSON을 이용한 역직렬화
    static {{ struct_name }} FromJSON(const rapidjson::Value& obj) {
        {{ struct_name }} c;
        c.id = obj["id"].GetInt();
        c.name = obj["name"].GetString();
        c.hp = obj["hp"].GetInt();
        std::string cls = obj["class"].GetString();
        if (cls == "Warrior") c.class_type = {{ enum_name }}::Warrior;
        else if (cls == "Mage") c.class_type = {{ enum_name }}::Mage;
        else if (cls == "Archer") c.class_type = {{ enum_name }}::Archer;
        return c;
    }
};

📁 codegen.py

import json
import jinja2

def main():
    with open("schema/character.schema.json") as f:
        schema = json.load(f)

    struct_name = schema["title"]
    enum_name = "CharacterClass"
    enum_values = schema["properties"]["class"]["enum"]

    env = jinja2.Environment(loader=jinja2.FileSystemLoader("template"))
    tmpl = env.get_template("class.hpp.jinja2")

    output = tmpl.render(
        struct_name=struct_name,
        enum_name=enum_name,
        enum_values=enum_values
    )

    with open("output/character.hpp", "w") as f:
        f.write(output)

if __name__ == "__main__":
    main()

🧪 3. 예제 main.cpp

📁 main.cpp

#include <iostream>
#include <rapidjson/document.h>
#include <fstream>
#include <sstream>
#include "character.hpp"

int main() {
    std::ifstream in("data.json");
    std::stringstream ss;
    ss << in.rdbuf();
    std::string json_str = ss.str();

    rapidjson::Document doc;
    doc.Parse(json_str.c_str());

    if (!doc.IsObject()) {
        std::cerr << "Invalid JSON\n";
        return 1;
    }

    Character c = Character::FromJSON(doc);

    std::cout << "ID: " << c.id << ", Name: " << c.name << ", HP: " << c.hp << "\n";
}

📄 예제 JSON 입력 (data.json)

{
  "id": 1001,
  "name": "Auron",
  "hp": 180,
  "class": "Warrior"
}

⚙️ CMake 설정

📁 CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(MMORPG_RapidJSON)

set(CMAKE_CXX_STANDARD 17)

include_directories(${CMAKE_SOURCE_DIR}/external/rapidjson/include)

add_executable(server main.cpp output/character.hpp)

external/rapidjson/include는 RapidJSON을 clone한 경로입니다.


📌 요약

항목 사용 도구 설명

JSON 파서 RapidJSON 매우 빠르고 가벼움, MMORPG 서버에 적합
코드 생성 Python + Jinja2 JSON Schema → 구조체 자동 생성
enum / struct 변환 직접 구현 RapidJSON DOM 기반 구조 파싱 지원