Skip to content

Latest commit

 

History

History
263 lines (235 loc) · 13.3 KB

(2023.7.16)Simple JSON 源码刨析 - 1[Margoo].md

File metadata and controls

263 lines (235 loc) · 13.3 KB
<style type="text/css"> /*提示:如果你看到了这行文字,那说明您的预览器不支持内嵌 CSS 代码,请使用 VSCode 阅读本 Markdown 文件*/ body{font-size:15px;color:#333;background:#fff;font-family:Helvetica, Arial, "PingFang SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "tohoma,sans-serif";margin:0;padding:10%}h1{font-size:2.2em;font-weight:700;line-height:1.1;padding-top:16px;margin-bottom:4px}h2, h3, h4, h5, h6{line-height:1.5em;margin-top:2.2em;margin-bottom:4px}h2{color:#ffffff !important;background-color:#ff9b98;border-left:12px solid #FF7E79;padding :1px 1px 1px 20px}h3{font-weight:700;font-size:1.2em;line-height:1.4;margin:10px 0 5px;padding-top:10px}h4{font-weight:700;text-transform:uppercase;font-size:1.1em;line-height:1.4;margin:10px 0 5px;padding-top:10px}h5, h6{font-size:.9em}h5{font-weight:bold;text-transform:uppercase}h6{font-weight:normal;color:#AAA}img{width:100%;border-radius:5px;display:block;margin-bottom:15px;height:auto}dl, ol, ul{margin-top:12px;margin-bottom:20px;padding-left:5%;line-height:1.8}p{margin:0 0 20px;padding:0;line-height:1.8}a{color:#f22f27;text-decoration:none}a:hover{color:#f55852;text-decoration:underline}a:focus{outline-offset:-2px}blockquote{font-size:1em;font-style:normal;padding:30px 38px;margin:0 0 15px;position:relative;line-height:1.8;text-indent:0;border:none;color:#888}blockquote:before{content:"“";left:12px;top:0;color:#E0E0E0;font-size:4em;font-family:Arial, serif;line-height:1em;font-weight:700;position:absolute}blockquote:after{content:"”";right:12px;bottom:-26px;color:#E0E0E0;font-size:4em;font-family:Arial, serif;line-height:1em;font-weight:700;position:absolute;bottom:-31px}strong, dfn{font-weight:700}em, dfn{font-style:italic;font-weight:400}del{text-decoration:line-through}pre{margin:0 0 10px;font-size:13px;line-height:1.42857;word-break:break-all;word-wrap:break-word;border-radius:4px;white-space:pre-wrap;display:block;background:#f8f8f8;padding:10px 20px;border:none;margin-bottom:25px;color:#666;font-family:Courier, sans-serif}code{color:#c7254e;background-color:#f9f2f4;border-radius:4px;font-family:Menlo, Monaco, Consolas, "Courier New", monospace;padding:2px 4px;font-size:90%}p>code{color:#c7264e;background-color:#f9f2f4;font-size:.95em;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}figure{margin:1em 0}figcaption{font-size:0.75em;padding:0.5em 2em;margin-bottom:2em}figure img{margin-bottom:0px}hr{border:0;height:1px;background:#333;background-image:linear-gradient(to right, #ccc, #333, #ccc)}ol p, ul p{margin-bottom:0px}li{margin-bottom:0.75em;margin-top:0.75em}ol#footnotes{font-size:0.95em;padding-top:1em;margin-top:1em;margin-left:0;border-top:1px solid #eaeaea;counter-reset:footer-counter;list-style:none;color:#555;padding-left:5%;margin:20px 0}ol#footnotes li{margin-bottom:10px;margin-left:16px;font-weight:400;line-height:2;list-style-type:none}ol#footnotes li:before{content:counter(footer-counter) ". ";counter-increment:footer-counter;font-weight:800;font-size:.95em}@keyframes highfade{0%{background-color:none}20%{background-color:yellow}100%{background-color:none}}@-webkit-keyframes highfade{0%{background-color:none}20%{background-color:yellow}100%{background-color:none}}a:target, ol#footnotes li:target, sup a:target{animation-name:highfade;animation-duration:2s;animation-iteration-count:1;animation-timing-function:ease-in-out;-webkit-animation-name:highfade;-webkit-animation-duration:2s;-webkit-animation-iteration-count:1;-webkit-animation-timing-function:ease-in-out}a:target{border:0;outline:0}animation-iteration-count:1;-webkit-animation-timing-function:ease-in-out}a:target{border:0;outline:0}tion-iteration-count:1;-webkit-animation-timing-function:ease-in-out}a:target{border:0;outline:0} </style>

每天一个技术点


本文作者:Margoo
发布时间:2023.7.16
内容概要:本文将会简单刨析一个 JSON 解析器的实现(第一章)

1. 前言

本文将会刨析我写的库,Simple JSON的实现,Simple JSON 的实现非常简单,只有一个 hpp 文件;下面是一个使用 Simple JSON 解析文件的实例:

#include "sJson.hpp"

int main()
{
    sJSONParser Parser(R"({
    "sites": [
        { "name":"codeforce" , "url":"www.codeforces.com", "rank":3 }, 
        { "name":"google" , "url":"www.google.com", "rank":2 }, 
        { "name":"github" , "url":"www.github.com", "rank":1 }
    ]
})");
    // 解析 JSON
    auto Root = Parser.Parse();

    // 序列化 JSON 对象
    printf("JSON in format : %s\n", sJSONWriter::WriteJSON(Root).c_str());
    printf("JSON in not format : %s\n\n", sJSONWriter::WriteJSON(Root, false).c_str());

    // 读取 JSON 文件
    for (auto Object = Root["sites"].ArrayBegin(); Object != Root["sites"].ArrayEnd(); ++Object)
    {
        auto ObjectExpand = sJSONElementFinder((*Object)->To<sJSONObject*>());
        for (auto Instance : ObjectExpand)
        {
            printf("<%s, ", Instance.first.c_str());
            if (sJSONString::Equal(**Instance.second)) {
                printf("%s> ", (**Instance.second->To<sJSONString*>()).c_str());
            }
            if (sJSONInt::Equal(**Instance.second)) {
                printf("%d> ", **Instance.second->To<sJSONInt*>());
            }
        }
        printf("\n");
    }

    return 0;
}

上面的代码会输出:

JSON in format : {
        "sites":[
                {
                        "name":"codeforce",
                        "rank":3,
                        "url":"www.codeforces.com"
                },
                {
                        "name":"google",
                        "rank":2,
                        "url":"www.google.com"
                },
                {
                        "name":"github",
                        "rank":1,
                        "url":"www.github.com"
                }
        ]
}
JSON in not format : {"sites":[{"name":"codeforce","rank":3,"url":"www.codeforces.com"},{"name":"google","rank":2,"url":"www.google.com"},{"name":"github","rank":1,"url":"www.github.com"}]}

<name, codeforce> <rank, 3> <url, www.codeforces.com>
<name, google> <rank, 2> <url, www.google.com>
<name, github> <rank, 1> <url, www.github.com>

本文会以此代码为切入点去解析 Simple JSON 的实现

2. sJSONParser

2.1 sJSONObject

让我们来关注 sJSONParser 的构造函数 sJSONParser::sJSONParser

sJSONParser(std::string Code) : RootObject(new sJSONObject()), Lexer(Code, &Status)
{
}

可以看到 sJSONParser 中初始化了一个对象 RootObjectLexer 对象,先关注 RootObject 对象,查看发现 RootObject 的类型为 sJSONObject,而 RootObject 则是代表 JSON 树的根节点。

这里再先说一下 Parser 的大概工作原理,Parser 实际上做的工作便是将 JSON 代码转换为一个树形结构储存在内存中,这个其实就是树其实就是 AST(Abstract Syntax Tree)抽象语法树,事实上生成 AST 树在现代语言中只不过是一个最上层的一环,但是在 JSON 的读取中我们只需要获得一个 AST 树就可以了。

再来说一些性内容:

{
    "glossary": {
        "title": "example glossary",
		"GlossDiv": {
            "title": "S",
			"GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
					"SortAs": "SGML",
					"GlossTerm": "Standard Generalized Markup Language",
					"Acronym": "SGML",
					"Abbrev": "ISO 8879:1986",
					"GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
						"GlossSeeAlso": ["GML", "XML"]
                    },
					"GlossSee": "markup"
                }
            }
        }
    }
}

在上面这个例子中,形如 "glossary""GlossDef" 的称之为键(Key),而引号过后接着的一律称为值(Value),一堆值和键称为键值对。

回过头来,再来关注 sJSONObject 的定义(此处略去一些成员函数):

/**
 * sJSON 树节点
 */
typedef class sJSONElementNode : public sJSONValue
{
public:
	sJSONElementNode()
	{
		Value = nullptr;
	}
	sJSONElementNode(const std::string &Tag, sJSONValue *Value)
	{
		this->Tag	= Tag;
		this->Value = Value;
	}
	sJSONElementNode(std::map<std::string, sJSONElementNode *> SetChildren) : Children(SetChildren), Value(nullptr)
	{
	}

public:
	sJSONValue								 *Value;
	std::string								  Tag;
	std::map<std::string, sJSONElementNode *> Children;
} sJSONObject;

可以看到 sJSONObject 实际上只是 sJSONElementNode 的别名,其继承自 sJSONValue,所以说,sJSONObject 实际上是一个值,之所以这么设计是因为在 JSON 中一个键对应的值可以是一个对象,而一个对象又包含很多值对,所以对于一个对象值其在代码实现中既可以做值也可以做 AST 节点也可以做值。

sJSONElementNode::Tag 则就是这个节点的键名(如果该节点有键名)。

sJSONObject 中还有一个指针 Value,这便是当前节点的值,这或许有点绕,这个类本身可以作为一个值,但是其又可以有一个值,难道是值中套了个值?实则不然,这个 Value 仅在当当前对象表示为 sJSONElementNode 的时候有效,而当其表示为一个值的时候是无效的,sJSONElementNode 中的三个构造函数就对应了这两种情况。

那么 sJSONObject 所继承的 sJSONValue 是什么呢,跳转到 sJSONValue 的定义如下:

/**
 * sJSON 值的基类
 */
class sJSONValue
{
public:
	sJSONValue()  = default;
	~sJSONValue() = default;

public:
	virtual __forceinline const sJSONValueType GetType() const = 0;
	virtual __forceinline const size_t		   GetHash() const
	{
		return 0;
	}

	template <class Object> Object To()
	{
		return static_cast<Object>(this);
	}
};

这个类的定义非常简单,sJSONValue 其实就是一个抽象的基类,其就是 JSON 的值,其中有一个纯虚函数 sJSONValue::GetType 和一个默认返回 0 的虚函数 sJSONValue::GetHash,先不管 sJSONVaue::GetHash 函数,先来看 sJSONValue::GetType 其返回一个 sJSONValueType,代表当前值的类型,sJSONValueType 的定义如下:

/**
 * sJSON 对象值的类型
 */
enum class sJSONValueType
{
	Value,
	Array,
	Object,
	Null
};

对象类型分为:实值、数组、对象、空,后三个很好理解,实值是什么意思呢?在 Simple JSON 中,将所有的实际值(例如数字,字符串,布尔值)都抽象成为了实值,实值没有对应的类型的实现,只有一个模板类如下:

/**
 * sJSON 中的实值
 */
template <class Type> class sJSONRealValue : public sJSONValue
{
public:
	sJSONRealValue(const Type &SetValue) : Value(SetValue)
	{
	}
	~sJSONRealValue() = default;

	__forceinline sJSONValueType const GetType() const override
	{
		return sJSONValueType::Value;
	}

	__forceinline const size_t GetHash() const override
	{
		return typeid(Type).hash_code();
	}

	static constexpr bool Equal(const sJSONValue *Judgement)
	{
		if (Judgement->GetType() != sJSONValueType::Value)
		{
			return false;
		}
		else
		{
			return Judgement->GetHash() == typeid(Type).hash_code();
		}
	}
	Type operator*()
	{
		return Value;
	}

public:
	Type Value;
};

using sJSONString  = sJSONRealValue<std::string>;
using sJSONInt	   = sJSONRealValue<int>;
using sJSONDouble  = sJSONRealValue<double>;
using sJSONBoolean = sJSONRealValue<bool>;

所以在 Simple JSON 中所有实值类型其实都是模板类 sJSONRealValue 的别名而已,而在 sJSONRealValue::GetHash 中使用了 C++ 中提供的 typeid 来返回当前类型的哈希值,以用来内部区分不同的实值类型。