整理代码
This commit is contained in:
commit
c7b4e178ec
364 changed files with 59691 additions and 0 deletions
201
util/xpack/LICENSE
Executable file
201
util/xpack/LICENSE
Executable file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
84
util/xpack/README-bson.md
Executable file
84
util/xpack/README-bson.md
Executable file
|
|
@ -0,0 +1,84 @@
|
|||
* 用于在C++结构体和bson之间互相转换
|
||||
* 这个库可以配合[mongoxclient](https://github.com/xyz347/mongoxclient)使用
|
||||
|
||||
# 目录
|
||||
- [encoder](#encoder)
|
||||
- [decoder](#decoder)
|
||||
- [bson types](#bsontypes)
|
||||
- [builder](#builder)
|
||||
- [重要说明](#重要说明)
|
||||
|
||||
## encoder
|
||||
用于将结构体转成bson格式。范例:
|
||||
```C++
|
||||
struct Test {
|
||||
int64_t id;
|
||||
std::string name;
|
||||
std::string email;
|
||||
XPACK(A(id, "bson:_id"), O(name, email));
|
||||
};
|
||||
|
||||
Test t;
|
||||
std::string data = xpack::bson::encode(t); // data就是t转成bson的数据
|
||||
```
|
||||
|
||||
## decoder
|
||||
用于将bson数据转成结构体
|
||||
用于将结构体转成bson格式。范例:
|
||||
```C++
|
||||
struct Test {
|
||||
int64_t id;
|
||||
std::string name;
|
||||
std::string email;
|
||||
XPACK(A(id, "bson:_id"), O(name, email));
|
||||
};
|
||||
|
||||
std::string data;
|
||||
// data = xxxx; data存储了相应的bson数据
|
||||
Test t;
|
||||
xpack::bson::decode(data, t);
|
||||
// xpack::bson::decode 还有另一个参数方式:static void decode(const uint8_t* data, size_t len, T &val)
|
||||
```
|
||||
|
||||
## bsontypes
|
||||
- date time: `bson_date_time_t`
|
||||
- timestamp: `bson_timestamp_t`
|
||||
- binary: `bson_binary_t`
|
||||
- regex: `bson_regex_t`
|
||||
- oid: `bson_oid_t`
|
||||
- decimal128: `bson_decimal128_t`
|
||||
|
||||
前4种是xbson额外定义的,后面两种是定义在libbson内的,为了统一,前4种也是定义在全局命名空间。
|
||||
|
||||
## builder
|
||||
**需要C++11或以上版本支持**。用json的格式来构造bson数据。查询接口中的query,一般只需要指定很少几个字段,这个场景用结构体表达不是很方便。用builder就会简单很多。基本用法是:
|
||||
1. 定义一个BsonBuilder:
|
||||
- 参数是一个json格式的字符串
|
||||
- 里面的双引号用单引号替代
|
||||
- 变量用问号作为占位符,问号后面可以加一个单词用来作为助记符,比如"?"和"?uid"是等效的
|
||||
- key也可以是变量,key作为变量,问号不用加引号
|
||||
- BsonBuilder是线程安全的,建议定义为static变量,这样json字符串只需解析一次
|
||||
范例:
|
||||
```C++
|
||||
static xpack::BsonBuilder bd("{'_id':?, ?:?}"); // 带占位符的builder
|
||||
static xpack::BsonBuilder empty("{}"); // 空bson
|
||||
static xpack::BsonBuilder student("{'type':'student'}"); // 不带占位符的builder
|
||||
```
|
||||
|
||||
2. 调用Encode函数来构造bson数据,Encode的参数对应的是各个占位符,因此参数个数应该和占位符一致
|
||||
比如对于上述的BsonBuilder
|
||||
```C++
|
||||
std::string data1 = bd.Encode(12345, "type", "master");
|
||||
std::string data2 = empty.Encode();
|
||||
std::string data3 = student.Encode();
|
||||
// 这些bson的数据可以用在mongoxclient的各个接口中
|
||||
```
|
||||
|
||||
3. 其他的一些API
|
||||
- EncodeAsJson 和Encode类似,但是输出的是json格式的数据,可以用于调试等场景(所以这个其实也是个JsonBuilder)
|
||||
- Error 如果构造BsonBuilder的json字符串有误,这个接口可以返回错误信息
|
||||
- static std::string En(const std::string&fmt, Args... args)。这个是把构造BsonBuilder和Encode合在一起了,不是很建议使用,建议用于调试,因为每次都要构造一次BsonBuilder
|
||||
|
||||
|
||||
## 重要说明
|
||||
- 依赖于[libbson](https://github.com/mongodb/libbson/tree/1.0.0),需自行安装
|
||||
407
util/xpack/README-en.md
Executable file
407
util/xpack/README-en.md
Executable file
|
|
@ -0,0 +1,407 @@
|
|||
xpack
|
||||
====
|
||||
* Used to convert between C++ structure and json/xml, bson is supported in [xbson](https://github.com/xyz347/xbson).
|
||||
* Only header files, no need to compile library files, so there is no Makefile.
|
||||
* Support MySQL, depends on `libmysqlclient-dev`, need to install by yourself. **not fully tested**
|
||||
* Support Sqlite, depends on [libsqlite3](https://cppget.org/libsqlite3), need to install it yourself. **not fully tested**
|
||||
* Support yaml, depend on [yaml-cpp](https://github.com/jbeder/yaml-cpp), need to install it yourself. **not fully tested**
|
||||
* For details, please refer to the example
|
||||
|
||||
------
|
||||
* [Quick start](#quick-start)
|
||||
* [Container Support](#container-support)
|
||||
* [FLAG](#flag)
|
||||
* [Alias](#alias)
|
||||
* [Bitfield](#bitfield)
|
||||
* [Inherit](#inherit)
|
||||
* [enum](#enum)
|
||||
* [Custom codec](#custom-codec)
|
||||
* [union](#union)
|
||||
* [Schema indeterminate type](#schema-indeterminate-type)
|
||||
* [Define macro outside the structure](#define-macro-outside-the-structure)
|
||||
* [Array](#array)
|
||||
* [Format indentation](#format-indentation)
|
||||
* [XML array](#xml-array)
|
||||
* [CDATA](#cdata)
|
||||
* [Qt support](#qt-support)
|
||||
* [Important note](#important-note)
|
||||
|
||||
Quick start
|
||||
----
|
||||
- Use macro `XPACK`(or `XPACK_OUT` if you don't want to change the structure) include structure members
|
||||
- Use xpack::json::encode to convert structure to json
|
||||
- Use xpack::json::decode to convert json to structure
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h" // include this header file for json or "xpack/xml.h" for xml
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct User {
|
||||
int id;
|
||||
string name;
|
||||
XPACK(O(id, name)); // Add XPACK at the end of structure, up to 99 'O' can be added, and each 'O' can contain up to 99 members
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
User u;
|
||||
string data = "{\"id\":12345, \"name\":\"xpack\"}";
|
||||
|
||||
xpack::json::decode(data, u); // json to structure
|
||||
cout<<u.id<<';'<<u.name<<endl;
|
||||
|
||||
string json = xpack::json::encode(u); // structure to json
|
||||
cout<<json<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Container Support
|
||||
----
|
||||
The following containers are currently supported (std)
|
||||
- vector
|
||||
- set
|
||||
- list
|
||||
- map<string, T>
|
||||
- map<integer, T> // only for json
|
||||
- unordered_map<string, T> (need C++11)
|
||||
- shared_ptr (need C++11)
|
||||
|
||||
FLAG
|
||||
----
|
||||
In the macro `XPACK`, variables need to be enclosed with letters, such as `XPACK(O(a,b))`, `XPACK` can contain multiple letters, and each letter can contain multiple variables. Currently supported letters are:
|
||||
- X Usage: X(F(flag1, flag2...), member1, member2,...) Multiple flags can be written in 'F', currently supported flags are:
|
||||
- 0 no flag
|
||||
- OE omitempty. When encoding, if the variable is 0 or an empty string or false, the variable is ignored
|
||||
- EN empty as null. When json encoding, encode empty variable as null(OE is ignore the variable)
|
||||
- M mandatory. When decoding, if the key corresponding to the variable does not exist, an exception is thrown
|
||||
- ATTR attribute. When xml encode, put the value in attribute
|
||||
- SL single line, When json encoding, put vector in single line
|
||||
- C Usage: C(customcodec, F(flag1,flags...), member1, member2,...) For custom codec function, please refer to [Custom codec](#custom-codec) for details
|
||||
- O Usage: O(member1, member2, ...) Same as X(F(0), member1, member2, ...) no flags
|
||||
- M Usage: M(member1, member2, ...) Same as X(F(M), member1, member2, ...) mandatory
|
||||
- A Usage: A(member1, alias1, member2, alias2...) Used when the key and the variable name are different, please refer to [Alias](#alias) for details
|
||||
- AF Usage: AF(F(flag1, flag2,...), member1, alias1, member2, alias2...) Alias with flags
|
||||
- B Usage: B(F(flag1, flag2, ...), member1, member2, ...) For bitfield, please refer to [Bitfield](#bitfield) for details. **bitfield not support alias**
|
||||
- I Usage: I(baseclass1, baseclass2....), baseclassx is parent class, please refer to [Inherit](#inherit) for details
|
||||
- E Usage: E(member1, member2) For enumeration variables that do not support C++11. **E not support alias**
|
||||
|
||||
Alias
|
||||
----
|
||||
- Used when the key and the variable name are different
|
||||
- Usage: A(member1, alias1, member2, alias2...) or AF(F(flag1, flag2,...), member1, alias1, member2, alias2...), alias's format is "x t:n"
|
||||
- x stands for global alias, not required
|
||||
- t stands for type(currently support json/xml/bson), n stands for type alias, type alias is not required
|
||||
- The order of precedence is: type alias, global alias, variable name
|
||||
- For example, `id bson:_id`, in bson will use `_id` and json/xml will use `id`
|
||||
- Type alias can take some type flags, format is "t:n,flag1,flag2,...", currently supported flags are:
|
||||
- cdata. For xml, indicates that it is cdata
|
||||
- sbs. For xml vector, In normal, `vector<int> nums` will be encoded into `<nums><nums>1</nums><nums>2</nums><nums>`, in sbs is `<nums>1</nums><nums>2</nums>`
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(A(uid, "id"), O(name)); // "uid" use alias "id"
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.uid<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Bitfield
|
||||
----
|
||||
- Use 'B' include bitfield members. **bitfield not support alias**
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
short ver:8;
|
||||
short len:8;
|
||||
string name;
|
||||
XPACK(B(F(0), ver, len), O(name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.ver<<endl;
|
||||
cout<<t.len<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Inherit
|
||||
----
|
||||
- Use 'I' include parent classes. If you don't need variables from the parent class, you don't need use 'I'
|
||||
- Parent class need add macro XPACK/XPACK_OUT
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct P1 {
|
||||
string mail;
|
||||
XPACK(O(mail));
|
||||
};
|
||||
|
||||
struct P2 {
|
||||
long version;
|
||||
XPACK(O(version));
|
||||
};
|
||||
|
||||
struct Test:public P1, public P2 {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(I(P1, P2), O(uid, name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"mail\":\"pony@xpack.com\", \"version\":2019, \"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.mail<<endl;
|
||||
cout<<t.version<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
enum
|
||||
----
|
||||
- If support C++11, enum is same as other type, use X/O/M/A is ok
|
||||
- Otherwise need to use 'E', usage: E(F(...), member1, member2, ...)
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum Enum {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
struct Test {
|
||||
string name;
|
||||
Enum e;
|
||||
XPACK(O(name), E(F(0), e));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"IPv4\", \"e\":1}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.e<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Custom codec
|
||||
----
|
||||
Used in scenarios where you want to define your own codec method, such as:
|
||||
- Wish to encode numeric types in string or hexadecimal
|
||||
- Don't want to encode the struct variable by variable:
|
||||
```C++
|
||||
struct Time {
|
||||
long ts; //unix timestamp
|
||||
};
|
||||
```
|
||||
Don't want to encode to {"ts":1218196800} but "2008-08-08 20:00:00"
|
||||
|
||||
There are two ways to achieve:
|
||||
- Use xtype. You can refer to this [example](example/xtype.cpp)
|
||||
- Use 'C' include members need to custome codec(Hereinafter referred to as the `C method`), You can refer to this [example](example/custom.cpp)
|
||||
|
||||
Both methods need to implement custom codec, but there are some differences:
|
||||
- xtype is at the type level, that is, once a certain type is encapsulated with xtype, the custom encode/decode will take effect for this type. xtype cannot be used for basic types (int/string, etc.)
|
||||
- The C method can support basic types (int/string, etc.) and non-basic types, but only works on variables contained in C, such as
|
||||
```C++
|
||||
int a;
|
||||
int b;
|
||||
XPACK(O(a), C(custome_int, F(0), b ))
|
||||
```
|
||||
Then "a" still uses the default codec, and "b" uses the custom codec.
|
||||
|
||||
1. xtype takes precedence over the XPACK macro, that is, if xtype is defined, the encode/decode of xtype will be used first
|
||||
2. The C method takes precedence over xtype, that is, the variables contained in C must use the codec method specified in C
|
||||
|
||||
With these two features, some more flexible codec control can be realized. For example, this [example](example/xtype_advance.cpp) realizes a function of encoding according to the variable situation. If Sub.type==1, then encode seq1, Otherwise encode seq2. `__x_pack_decode` and `__x_pack_encode` are the decode/encode functions added to the structure by the XPACK macro, and the custom codec function can call the default codec function of xpack through these functions.
|
||||
|
||||
union
|
||||
----
|
||||
Unions can be handled using [Custom codec](#custom-codec). You can refer to this [example](example/union1.cpp)
|
||||
|
||||
Array
|
||||
----
|
||||
- When decoding, if the number of elements exceeds the length of the array, it will be truncated
|
||||
- The char array needs to have a '\0' terminator
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Test {
|
||||
char name[64];
|
||||
char email[64];
|
||||
XPACK(O(name, email));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"Pony\", \"email\":\"pony@xpack.com\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.email<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Schema indeterminate type
|
||||
----
|
||||
- Json only
|
||||
- Use [xpack::JsonData](json_data.h) for this kind of content
|
||||
- You can refer to this [example](example/json-data.cpp)
|
||||
- The main APIs for xpack::JsonData are:
|
||||
- Type. To get the field type
|
||||
- IsXXX. To check is the field type is xxx, same as `return Type()==xxxx;`
|
||||
- GetXXX. To get the field value
|
||||
- operator bool. To check is't a valid xpack::JsonData
|
||||
- Size. To get the array's elements number
|
||||
- `operator [](size_t index)`. Used to get the index element in array
|
||||
- `operator [](const char *key)`. Used to get the element by key in object
|
||||
- Iterator:
|
||||
- Begin. Get the first element's iterator
|
||||
- Next. Get the next iterator
|
||||
- Key. Get the key of iterator
|
||||
- Val. Get the value of iterator
|
||||
|
||||
Define macro outside the structure
|
||||
----
|
||||
- Use `XPACK_OUT` instead of `XPACK` to include structure members
|
||||
- `XPACK_OUT` must define in global namespace
|
||||
|
||||
```c++
|
||||
#include <sys/time.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
*/
|
||||
|
||||
// timeval is thirdparty struct
|
||||
XPACK_OUT(timeval, O(tv_sec, tv_usec));
|
||||
|
||||
struct T {
|
||||
int a;
|
||||
string b;
|
||||
timeval t;
|
||||
XPACK(O(a, b, t));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
T t;
|
||||
T r;
|
||||
t.a = 123;
|
||||
t.b = "xpack";
|
||||
t.t.tv_sec = 888;
|
||||
t.t.tv_usec = 999;
|
||||
string s = xpack::json::encode(t);
|
||||
cout<<s<<endl;
|
||||
xpack::json::decode(s, r);
|
||||
cout<<r.a<<','<<r.b<<','<<r.t.tv_sec<<','<<r.t.tv_usec<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Format indentation
|
||||
----
|
||||
- The default encode is not indented, and the readability is not good
|
||||
- If indentation is required, it can be controlled by the last two parameters of encode:
|
||||
- indentCount Indicates the number of characters for indentation, <0 means no indentation, 0 means newline but no indentation
|
||||
- indentChar Characters that represent indentation, use spaces or tabs
|
||||
|
||||
XML array
|
||||
----
|
||||
- Arrays use variable names as element labels by default, such as "ids":[1,2,3] will be encoded as:
|
||||
``` xml
|
||||
<ids>
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
</ids>
|
||||
```
|
||||
- You can use alias to change the label name. For example: A(ids,"xml:ids,vl@id"), vl@id means to use id as label:
|
||||
``` xml
|
||||
<ids>
|
||||
<id>1</id>
|
||||
<id>2</id>
|
||||
<id>3</id>
|
||||
</ids>
|
||||
```
|
||||
- If want to encode array element side by side, can use `sbs` flag. For example: `A(ids, "xml:ids,sbs")`. **Note that the sbs tag can only be used for arrays(vector), and it may crash if used elsewhere**
|
||||
``` xml
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
```
|
||||
|
||||
CDATA
|
||||
----
|
||||
- For xml CDATA, need to use `cdata` flag. For example: A(data, "xml:data,cdata")
|
||||
- variable type must be std::string
|
||||
- Non-cdata types can also add cdata flag, which will be processed as ordinary strings
|
||||
|
||||
Qt support
|
||||
----
|
||||
- Modify [config.h](config.h) to enable XPACK_SUPPORT_QT(or enable it in compile flags)
|
||||
- Currently supports: QString/QMap/QList/QVector
|
||||
|
||||
|
||||
Important note
|
||||
----
|
||||
- Try not to start the variable name with __x_pack, otherwise it may conflict with the library.
|
||||
- vc6 is not supported
|
||||
- msvc has only been tested on vs2019
|
||||
- The serialization and deserialization of json uses [rapidjson](https://github.com/Tencent/rapidjson) (November 2018 edition)
|
||||
- The deserialization of xml uses [rapidxml](http://rapidxml.sourceforge.net)
|
||||
- The serialization of xml is written by myself, without reference to RFC, there may be some differences from the standard.
|
||||
418
util/xpack/README.md
Executable file
418
util/xpack/README.md
Executable file
|
|
@ -0,0 +1,418 @@
|
|||
xpack
|
||||
====
|
||||
[English](README-en.md)
|
||||
* 用于在C++结构体和json/xml/yaml/bson/mysql/sqlite之间互相转换
|
||||
* 只有头文件, 无需编译库文件,所以也没有Makefile。
|
||||
* 支持bson,依赖于`libbson-1.0`,需自行安装。**未经充分测试**,具体请参考[README](README-bson.md)
|
||||
* 支持MySQL,依赖于`libmysqlclient-dev`,需自行安装。**未经充分测试**
|
||||
* 支持Sqlite,依赖于[libsqlite3](https://cppget.org/libsqlite3),需自行安装。**未经充分测试**
|
||||
* 支持yaml,依赖于[yaml-cpp](https://github.com/jbeder/yaml-cpp),需自行安装。**未经充分测试**
|
||||
* 具体可以参考example的例子
|
||||
|
||||
------
|
||||
* [基本用法](#基本用法)
|
||||
* [容器支持](#容器支持)
|
||||
* [FLAG](#flag)
|
||||
* [别名](#别名)
|
||||
* [位域](#位域)
|
||||
* [继承](#继承)
|
||||
* [枚举](#枚举)
|
||||
* [自定义编解码](#自定义编解码)
|
||||
* [union](#union)
|
||||
* [不定类型](#不定类型)
|
||||
* [数组](#数组)
|
||||
* [第三方类和结构体](#第三方类和结构体)
|
||||
* [格式化缩进](#格式化缩进)
|
||||
* [XML数组](#xml数组)
|
||||
* [CDATA](#cdata)
|
||||
* [Qt支持](#qt支持)
|
||||
* [MySQL](#mysql)
|
||||
* [重要说明](#重要说明)
|
||||
|
||||
基本用法
|
||||
----
|
||||
- 结构体后面用XPACK宏包含各个变量,XPACK内还需要一个字母,不同字母的意义请参考[FLAG](#flag)
|
||||
- 用xpack::json::encode把结构体转json
|
||||
- 用xpack::json::decode把json转结构体
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h" // Json包含这个头文件,xml则包含xpack/xml.h
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct User {
|
||||
int id;
|
||||
string name;
|
||||
XPACK(O(id, name)); // 添加宏定义XPACK在结构体定义结尾
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
User u;
|
||||
string data = "{\"id\":12345, \"name\":\"xpack\"}";
|
||||
|
||||
xpack::json::decode(data, u); // json转结构体
|
||||
cout<<u.id<<';'<<u.name<<endl;
|
||||
|
||||
string json = xpack::json::encode(u); // 结构体转json
|
||||
cout<<json<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
容器支持
|
||||
----
|
||||
目前支持下列容器(std)
|
||||
- vector
|
||||
- set
|
||||
- list
|
||||
- map<string, T>
|
||||
- map<integer, T> // 仅JSON,XML不支持
|
||||
- unordered_map<string, T> (需要C++11支持)
|
||||
- shared_ptr (需要C++11支持)
|
||||
|
||||
FLAG
|
||||
----
|
||||
宏XPACK里面,需要用字母将变量包含起来,比如XPACK(O(a,b)),XPACK可以包含多个字母,每个字母可以包含多个变量。目前支持的字母有:
|
||||
- X。格式是X(F(flag1, flag2...), member1, member2,...) F里面包含各种FLAG,目前支持的有:
|
||||
- 0 没有任何FLAG
|
||||
- OE omitempty,encode的时候,如果变量是0或者空字符串或者false,则不生成对应的key信息
|
||||
- EN empty as null, 用于json的encode,OE是直接不生成empty的字段,EN则是生成一个null
|
||||
- M mandatory,decode的时候,如果这个字段不存在,则抛出异常,用于一些id字段。
|
||||
- ATTR attribute,xml encode的时候,把值放到attribute里面。
|
||||
- SL single line, json encode的时候,对于数组,放在一行里面
|
||||
- C。格式是C(customcodec, F(flag1,flags...), member1, member2,...)用于自定义编解码函数,详情请参考[自定义编解码](#自定义编解码)
|
||||
- O。等价于X(F(0), ...) 没有任何FLAG。
|
||||
- M。等价于X(F(M),...) 表示这些字段是必须存在的。
|
||||
- A。[别名](#别名),A(member1, alias1, member2, alias2...),用于变量和key名不一样的情况
|
||||
- AF。带FLAG的[别名](#别名),AF(F(flag1, flag2,...), member1, alias1, member2, alias2...)
|
||||
- B。[位域](#位域),B(F(flag1, flag2, ...), member1, member2, ...) **位域不支持别名**
|
||||
- I。[继承](#继承),I(baseclass1, baseclass2....),里面放父类
|
||||
- E。[枚举](#枚举):
|
||||
- 如果编译器支持C++11,不需要用E,枚举可以放X/O/M/A里面。
|
||||
- 否则枚举只能放E里面,不支持别名
|
||||
|
||||
别名
|
||||
----
|
||||
- 用于变量名和key名不一致的场景
|
||||
- 格式是A(变量,别名....)或者AF(F(flags), 变量,别名....),别名的格式是"x t:n"的格式
|
||||
- x表示全局别名,t表示类型(目前支持json、xml、bson),n表示类型下的别名
|
||||
- 全局别名可以没有,比如`json:_id`是合法的
|
||||
- 类型别名可以没有,比如`_id`是合法的
|
||||
- 有类型别名优先用类型别名,否则用全局别名,都没有,则用变量名
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(A(uid, "id"), O(name)); // "uid"的别名是"id"
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.uid<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
位域
|
||||
----
|
||||
- 使用"B"来包含位域变量,**位域不支持别名**
|
||||
|
||||
``` C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
short ver:8;
|
||||
short len:8;
|
||||
string name;
|
||||
XPACK(B(F(0), ver, len), O(name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.ver<<endl;
|
||||
cout<<t.len<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
继承
|
||||
----
|
||||
- 使用"I"来包含父类。需要用到父类的变量就包含,用不到可以不包含。
|
||||
- 父类的父类也需要包含,比如class Base; class Base1:public Base; class Base2:public Base1;那么在Base2中需要I(Base1, Base)
|
||||
- 父类也需要定义XPACK/XPACK_OUT宏。
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct P1 {
|
||||
string mail;
|
||||
XPACK(O(mail));
|
||||
};
|
||||
|
||||
struct P2 {
|
||||
long version;
|
||||
XPACK(O(version));
|
||||
};
|
||||
|
||||
struct Test:public P1, public P2 {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(I(P1, P2), O(uid, name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"mail\":\"pony@xpack.com\", \"version\":2019, \"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.mail<<endl;
|
||||
cout<<t.version<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
枚举
|
||||
----
|
||||
- 如果编译器支持C++11,则枚举和普通变量名一样,放X/O/M/A里面皆可。
|
||||
- 否则需要放到E里面,格式是E(F(...), member1, member2, ...)
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum Enum {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
struct Test {
|
||||
string name;
|
||||
Enum e;
|
||||
XPACK(O(name), E(F(0), e));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"IPv4\", \"e\":1}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.e<<endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
自定义编解码
|
||||
----
|
||||
应用场景
|
||||
- 有些基础类型想用自定义方式编码,比如用字符串的方式来编码整数/浮点数
|
||||
- 部分类型可能不想按结构体变量逐个编码,比如定义了一个时间结构体:
|
||||
```C++
|
||||
struct Time {
|
||||
long ts; //unix timestamp
|
||||
};
|
||||
```
|
||||
并不希望编码成{"ts":1218196800} 这种格式,而是希望编码成"2008-08-08 20:00:00"这种格式。
|
||||
|
||||
这里有两种方式:
|
||||
- 使用xtype,可以参考[例子](example/xtype.cpp)
|
||||
- 用C来包含需要自定义编解码的变量(下面简称C方法),可以参考[例子](example/custom.cpp)
|
||||
|
||||
两种方法本质上都是自己去实现encode/decode,但是有以下区别:
|
||||
- xtype是类型级别的,也就是一旦某个类型用xtype封装之后,那么自定义的encode/decode就对这个类型生效。xtype无法作用于基本类型(int/string等)
|
||||
- C方法能支持基本类型(int/string等)和非基本类型,但是仅作用于用C包含的变量,比如int a;int b; O(a), C(custome_int, F(0), b);那么a还是用默认的编解码,b才是用自定义的编解码。
|
||||
|
||||
1. xtype优先于XPACK宏,也就是定义了xtype的,会优先使用xtype的encode/decode
|
||||
2. C方法优先于xtype,也就是用C包含的变量,一定会用C里面指定的编解码方法。
|
||||
|
||||
用这两个特性,可以实现一些比较灵活的编解码控制,比如这个[例子](example/xtype_advance.cpp)实现了一个根据变量情况来编码的功能,如果Sub.type==1则encode seq1,否则encode seq2. `__x_pack_decode`和`__x_pack_encode`是XPACK宏给结构体添加的decode/encode函数,自定义编解码函数可以通过这些函数调用xpack默认的编解码功能。
|
||||
|
||||
union
|
||||
----
|
||||
可以使用[自定义编解码](#自定义编解码)来处理联合体,可以参考[范例](example/union1.cpp)
|
||||
|
||||
数组
|
||||
----
|
||||
- decode的时候如果元素个数超过数组的长度,会截断
|
||||
- char数组按有\0结束符处理
|
||||
|
||||
```C++
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Test {
|
||||
char name[64];
|
||||
char email[64];
|
||||
XPACK(O(name, email));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Test t;
|
||||
string json="{\"name\":\"Pony\", \"email\":\"pony@xpack.com\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.email<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
不定类型
|
||||
----
|
||||
- 用于json的schema不确定的场景
|
||||
- 用[xpack::JsonData](json_data.h)来接收这些信息
|
||||
- 可以参考[例子](example/json-data.cpp)
|
||||
- xpack::JsonData主要的方法有:
|
||||
- Type。用于获取类型
|
||||
- IsXXX系列函数。用于判断是否是某种类型,基本等价于return Type()==xxxx;
|
||||
- GetXXX系列函数。用来提取值。
|
||||
- 重载bool。用来判断是否是一个合法的JsonData。
|
||||
- Size。用于数组类型判断元素的个数
|
||||
- `operator [](size_t index)` 用来取数组的第index个元素(从0开始)
|
||||
- `operator [](const char *key)` 用来根据key取Object类型的元素
|
||||
- Begin。用来遍历Object的元素,取第一个。
|
||||
- Next。配合Begin使用,获取下一个元素。
|
||||
- Key。配置Begin和Next使用,遍历的时候获取Key
|
||||
|
||||
第三方类和结构体
|
||||
----
|
||||
- 用XPACK_OUT而非XPACK来包含变量
|
||||
- XPACK_OUT必须定义在全局命名空间
|
||||
|
||||
```c++
|
||||
#include <sys/time.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
struct timeval {
|
||||
time_t tv_sec;
|
||||
suseconds_t tv_usec;
|
||||
};
|
||||
*/
|
||||
|
||||
// timeval is thirdparty struct
|
||||
XPACK_OUT(timeval, O(tv_sec, tv_usec));
|
||||
|
||||
struct T {
|
||||
int a;
|
||||
string b;
|
||||
timeval t;
|
||||
XPACK(O(a, b, t));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
T t;
|
||||
T r;
|
||||
t.a = 123;
|
||||
t.b = "xpack";
|
||||
t.t.tv_sec = 888;
|
||||
t.t.tv_usec = 999;
|
||||
string s = xpack::json::encode(t);
|
||||
cout<<s<<endl;
|
||||
xpack::json::decode(s, r);
|
||||
cout<<r.a<<','<<r.b<<','<<r.t.tv_sec<<','<<r.t.tv_usec<<endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
格式化缩进
|
||||
----
|
||||
- encode缺省生成的json/xml是没有缩进的,适合程序使用,如果让人读,可以进行缩进。
|
||||
- encode的最后两个参数控制
|
||||
- indentCount 表示缩进的字符数,<0表示不缩进,0则是换行但是不缩进
|
||||
- indentChar 表示缩进的字符,用空格或者制表符
|
||||
|
||||
XML数组
|
||||
----
|
||||
- 数组默认会用变量名作为元素的标签,比如"ids":[1,2,3],对应的xml是:
|
||||
``` xml
|
||||
<ids>
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
</ids>
|
||||
```
|
||||
- 可以用别名的方式来控制数组的元素的标签,比如A(ids,"xml:ids,vl@id"),vl后面跟着一个@xx,xx就是数组的标签,生成的结果就是:
|
||||
``` xml
|
||||
<ids>
|
||||
<id>1</id>
|
||||
<id>2</id>
|
||||
<id>3</id>
|
||||
</ids>
|
||||
```
|
||||
- 如果希望数组直接展开,而不是在外面包一层,可以用别名加"sbs"的flag来实现,比如A(ids, "xml:ids,sbs"),**注意,sbs标签仅能用于数组,其他地方使用可能会崩溃**
|
||||
``` xml
|
||||
<ids>1</ids>
|
||||
<ids>2</ids>
|
||||
<ids>3</ids>
|
||||
```
|
||||
|
||||
CDATA
|
||||
----
|
||||
- 对于CDATA类型,需要用"cdata"的flag来实现,比如A(data, "xml:data,cdata")
|
||||
- cdata只能用std::string来接收
|
||||
- 如果变量对应的xml不是CDATA结构,会按普通字符串来处理比如`<data>hello</data>`也可以解析成功
|
||||
|
||||
Qt支持
|
||||
----
|
||||
- 修改config.h,开启XPACK_SUPPORT_QT这个宏(或者在编译选项开启)
|
||||
- 当前支持 QString/QMap/QList/QVector
|
||||
|
||||
MySQL
|
||||
----
|
||||
- 目前仅支持decode,还不支持encode
|
||||
- 未经过完整测试,使用需要谨慎
|
||||
- 当前支持类型有:
|
||||
- string。简单测试。
|
||||
- 整型。简单测试。
|
||||
- 浮点型。未测试。
|
||||
- 用整型(比如time_t)接收TIME/DATETIME/TIMESTAMP。未测试。
|
||||
- 自定义类型转换,is_xpack_mysql_xtype,类似于xtype。未测试。
|
||||
- api有两个(xpack::mysql::) :
|
||||
- `static void decode(MYSQL_RES *result, T &val)`
|
||||
- 用来将MYSQL_RES转成结构体或者vector<>,如果是非vector,则只转换第一个row
|
||||
- `static void decode(MYSQL_RES *result, const std::string&field, T &val)`
|
||||
- 用来解析某个字段,用于只想获得某个字段内容的场景,比如select id from mytable where name = lilei,只想获得id信息。val支持vector
|
||||
|
||||
|
||||
重要说明
|
||||
----
|
||||
- 变量名尽量不要用__x_pack开头,不然可能会和库有冲突。
|
||||
- vc6不支持。
|
||||
- msvc没有做很多测试,只用2019做过简单测试。
|
||||
- json的序列化反序列化用的是[rapidjson](https://github.com/Tencent/rapidjson)
|
||||
- xml的反序列化用的是[rapidxml](http://rapidxml.sourceforge.net)
|
||||
- xml的序列化是我自己写的,没有参考RFC,可能有和标准不一样的地方.
|
||||
- 有疑问可以加QQ群878041110
|
||||
54
util/xpack/bson.h
Executable file
54
util/xpack/bson.h
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_H
|
||||
#define __X_PACK_BSON_H
|
||||
|
||||
#include "bson_decoder.h"
|
||||
#include "bson_encoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X // support c++11 or later
|
||||
#include "bson_builder.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class bson {
|
||||
public:
|
||||
template <class T>
|
||||
static void decode(const std::string &data, T &val) {
|
||||
BsonDecoder de;
|
||||
de.decode(data, val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void decode(const uint8_t* data, size_t len, T &val) {
|
||||
BsonDecoder de;
|
||||
de.decode(data, len, val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string encode(const T &val) {
|
||||
BsonEncoder en;
|
||||
return en.encode(val);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
588
util/xpack/bson_builder.h
Executable file
588
util/xpack/bson_builder.h
Executable file
|
|
@ -0,0 +1,588 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_BUILDER_H
|
||||
#define __X_PACK_BSON_BUILDER_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include "bson_encoder.h"
|
||||
|
||||
#ifndef X_PACK_SUPPORT_CXX0X // support c++11 or later
|
||||
#error "need c++11 or later"
|
||||
#endif
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class BsonBuilder {
|
||||
enum {
|
||||
Unknow = 0,
|
||||
ObjectBegin = 1<<0,
|
||||
ObjectEnd = 1<<1,
|
||||
ArrayBegin = 1<<2,
|
||||
ArrayEnd = 1<<3,
|
||||
Comma = 1<<4,
|
||||
Colon = 1<<5,
|
||||
Integer = 1<<6,
|
||||
Float = 1<<7,
|
||||
String = 1<<8,
|
||||
Bool = 1<<9,
|
||||
Variable = 1<<10,
|
||||
BEof = 1<<11
|
||||
};
|
||||
|
||||
std::string tokenName(int type) const {
|
||||
std::string ret;
|
||||
if (0 != (ObjectBegin&type)) {
|
||||
ret += "/{";
|
||||
}
|
||||
if (0 != (ObjectEnd&type)) {
|
||||
ret += "/}";
|
||||
}
|
||||
if (0 != (ArrayBegin&type)) {
|
||||
ret += "/[";
|
||||
}
|
||||
if (0 != (ArrayEnd&type)) {
|
||||
ret += "/]";
|
||||
}
|
||||
if (0 != (Comma&type)) {
|
||||
ret += "/,";
|
||||
}
|
||||
if (0 != (Colon&type)) {
|
||||
ret += "/:";
|
||||
}
|
||||
if (0 != ((Float|Integer|Bool)&type)) {
|
||||
ret += "/number/bool";
|
||||
}
|
||||
if (0 != (String&type)) {
|
||||
ret += "/string";
|
||||
}
|
||||
if (0 != (Variable&type)) {
|
||||
ret += "/variable";
|
||||
}
|
||||
|
||||
if (!ret.empty()) {
|
||||
ret = ret.substr(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
struct Token {
|
||||
int type; // see enum
|
||||
union {
|
||||
const char *sval;
|
||||
long lval;
|
||||
double dval;
|
||||
bool bval;
|
||||
};
|
||||
Token():type(Unknow),sval(NULL){}
|
||||
};
|
||||
struct Item {
|
||||
Token tk;
|
||||
const char *key;
|
||||
bool kvar; // key is variable
|
||||
Item():tk(),key(NULL), kvar(false) {
|
||||
}
|
||||
};
|
||||
struct Encoder {
|
||||
const std::vector<const Item*>* items;
|
||||
BsonWriter wr;
|
||||
XEncoder<BsonWriter> en;
|
||||
|
||||
size_t idx; // items index;
|
||||
size_t vidx; // variable index;
|
||||
|
||||
std::vector<std::string> vkeys; // store variable key
|
||||
Item tmpIt; // key:value when key is a variable, copy item to here
|
||||
Item *pIt; // point to tmpIt
|
||||
|
||||
std::vector<size_t> arrayIndex;
|
||||
std::vector<const char*> objKeys; // store object key. use in object end
|
||||
std::vector<const char*> arrKeys; // store array key, use in array end
|
||||
|
||||
Encoder(const std::vector<const Item*>&its):items(&its), en(wr), idx(0), vidx(0), pIt(NULL){}
|
||||
|
||||
// array key. index: "0", "1", "2", "3"
|
||||
const char *Key(const char *raw) {
|
||||
if (NULL != raw) {
|
||||
return raw;
|
||||
} else if (arrayIndex.size()>0) {
|
||||
size_t idx = arrayIndex.size() - 1;
|
||||
return wr.IndexKey(arrayIndex[idx]++);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
BsonBuilder(const std::string& _fmt):raw(_fmt),en(NULL) {
|
||||
dup = new char[raw.length()+1];
|
||||
strcpy(dup, raw.c_str());
|
||||
if (parse()) {
|
||||
for (size_t i=0; i<items.size(); ++i) {
|
||||
if (items[i]->kvar || items[i]->tk.type==Variable) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no variable. pre build it
|
||||
bstr = Encode();
|
||||
}
|
||||
}
|
||||
|
||||
~BsonBuilder() {
|
||||
if (NULL != dup) {
|
||||
for (size_t i=0; i<items.size(); ++i) {
|
||||
delete items[i];
|
||||
}
|
||||
delete[] dup;
|
||||
dup = NULL;
|
||||
} else if (NULL != en) {
|
||||
delete en;
|
||||
en = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Error() const {
|
||||
return fmtErr;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string Encode(Args... args) {
|
||||
if (!bstr.empty()) {
|
||||
return bstr;
|
||||
} else if (!fmtErr.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
BsonBuilder bd(*this);
|
||||
bd.iencode(args...);
|
||||
bd.end(NULL);
|
||||
return bd.en->en.String();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
std::string EncodeAsJson(Args... args) {
|
||||
if (!fmtErr.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
BsonBuilder bd(*this);
|
||||
bd.iencode(args...);
|
||||
bd.end(NULL);
|
||||
|
||||
return bd.en->wr.Json();
|
||||
}
|
||||
template <typename... Args>
|
||||
static std::string En(const std::string&fmt, Args... args) {
|
||||
BsonBuilder bb(fmt);
|
||||
return bb.Encode(args...);
|
||||
}
|
||||
|
||||
private: // encoder
|
||||
BsonBuilder(const BsonBuilder&bd):dup(NULL) {
|
||||
en = new Encoder(bd.items);
|
||||
}
|
||||
|
||||
// implement iencode()/iencode(T)/iencode(T, Args...) to expand template arguments
|
||||
void iencode() {
|
||||
}
|
||||
void iencode(const char*val) { // xencoder not allow pointer
|
||||
std::string s(val);
|
||||
encode(s);
|
||||
++en->vidx;
|
||||
}
|
||||
template <typename T>
|
||||
void iencode(const T &val) {
|
||||
encode(val);
|
||||
++en->vidx;
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void iencode(const T& first, Args... args) {
|
||||
iencode(first);
|
||||
iencode(args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
BsonBuilder& encode(const T &val) {
|
||||
// encode data items without variable
|
||||
for (; en->idx<en->items->size(); ++en->idx) {
|
||||
const Item *it = en->items->at(en->idx);
|
||||
if ((!it->kvar) && it->tk.type!=Variable) {
|
||||
add(it, 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (en->idx >= en->items->size()) { // finish
|
||||
return *this;
|
||||
} else if (NULL != en->pIt) { // key:val. key and val is variable, key replaced in last encode
|
||||
add(en->pIt, val);
|
||||
en->pIt = NULL;
|
||||
++en->idx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Item *it = en->items->at(en->idx);
|
||||
if (it->kvar) { // key:val and key is variable, we fill string to key
|
||||
en->tmpIt = *it; // copy item info
|
||||
en->pIt = &en->tmpIt;
|
||||
en->pIt->key = dumpStr(val); // dump key string
|
||||
en->pIt->kvar = false;
|
||||
if (it->tk.type != Variable) { // value not variable
|
||||
add(en->pIt, 1);
|
||||
en->pIt = NULL;
|
||||
++en->idx;
|
||||
}
|
||||
} else { // val is variable
|
||||
add(it, val);
|
||||
++en->idx;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// add items to encoder
|
||||
template <typename T>
|
||||
void add(const Item *it, const T&val) {
|
||||
const char *key = en->Key(it->key);
|
||||
|
||||
switch (it->tk.type) {
|
||||
case ObjectBegin:
|
||||
en->en.ob(key);
|
||||
en->objKeys.push_back(key);
|
||||
break;
|
||||
case ObjectEnd:
|
||||
en->en.oe(en->objKeys.back());
|
||||
en->objKeys.pop_back();
|
||||
break;
|
||||
case ArrayBegin:
|
||||
en->arrayIndex.push_back(0);
|
||||
en->en.ab(key);
|
||||
en->arrKeys.push_back(key);
|
||||
break;
|
||||
case ArrayEnd:
|
||||
en->arrayIndex.pop_back();
|
||||
en->en.ae(en->arrKeys.back());
|
||||
en->arrKeys.pop_back();
|
||||
break;
|
||||
case Integer:
|
||||
en->en.add(key, it->tk.lval);
|
||||
break;
|
||||
case Float:
|
||||
en->en.add(key, it->tk.dval);
|
||||
break;
|
||||
case String:
|
||||
en->en.add(key, std::string(it->tk.sval));
|
||||
break;
|
||||
case Bool:
|
||||
en->en.add(key, it->tk.bval);
|
||||
break;
|
||||
case Variable:
|
||||
en->en.add(key, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// encode the last none variable item
|
||||
void end(std::string *err) {
|
||||
for (; en->idx<en->items->size(); ++en->idx) {
|
||||
const Item *it = en->items->at(en->idx);
|
||||
if (it->kvar || it->tk.type==Variable) {
|
||||
if (NULL != err) {
|
||||
*err = "less variable";
|
||||
}
|
||||
return;
|
||||
}
|
||||
add(it, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// type to const char*
|
||||
const char *dumpStr(const std::string&str) {
|
||||
en->vkeys.push_back(str);
|
||||
return en->vkeys[en->vkeys.size()-1].c_str();
|
||||
}
|
||||
const char *dumpStr(const char *key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const char *dumpStr(const T&val) {
|
||||
(void)val;
|
||||
std::string err = "variable "+Util::itoa(en->vidx)+" is a key, must be std::string or const char*";
|
||||
throw std::runtime_error(err);
|
||||
return "";
|
||||
}
|
||||
|
||||
bool isEnd(char ch) {
|
||||
return ch==' ' || ch==':' || ch==',' || ch=='}' || ch==']'|| ch=='\0';
|
||||
}
|
||||
|
||||
// a simple bson string parser
|
||||
bool parse() {
|
||||
std::vector<char> stack;
|
||||
Item *item;
|
||||
char *p = dup;
|
||||
char *end = p;
|
||||
int keyIndex = -1;
|
||||
char ch;
|
||||
bool waitkey = false; // {key:value, expect key
|
||||
|
||||
int exp = ObjectBegin; // expect type
|
||||
while (true) {
|
||||
item = new Item;
|
||||
p = end;
|
||||
nextToken(p, &end, item->tk);
|
||||
|
||||
if (item->tk.type == BEof) {
|
||||
delete item;
|
||||
if (!fmtErr.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stack.size() > 0) {
|
||||
if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
fmtErr = "miss } at the end of string";
|
||||
} else {
|
||||
fmtErr = "miss ] at the end of string";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (item->tk.type == Unknow) {
|
||||
fmtErr = "unknow token:";
|
||||
fmtErr += p;
|
||||
delete item;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((item->tk.type&exp) == 0) {
|
||||
fmtErr = "unexpected token. expect["+tokenName(exp)+"]. but get["+tokenName(item->tk.type)+"]";
|
||||
if (NULL != item->tk.sval) {
|
||||
fmtErr += ". in [";
|
||||
fmtErr += item->tk.sval;
|
||||
fmtErr += "]";
|
||||
}
|
||||
delete item;
|
||||
break;
|
||||
}
|
||||
|
||||
// key:value parse value done
|
||||
if (keyIndex >= 0) {
|
||||
const Item *it = items[keyIndex];
|
||||
items.pop_back();
|
||||
keyIndex = -1;
|
||||
if (it->tk.type == String) {
|
||||
item->key = it->tk.sval;
|
||||
} else {
|
||||
item->kvar = true;
|
||||
}
|
||||
delete it;
|
||||
}
|
||||
|
||||
switch (item->tk.type) {
|
||||
case ObjectBegin:
|
||||
items.push_back(item);
|
||||
exp = ObjectEnd | Variable | String;
|
||||
stack.push_back('{');
|
||||
waitkey = true;
|
||||
break;
|
||||
case ObjectEnd:
|
||||
waitkey = false;
|
||||
case ArrayEnd:
|
||||
items.push_back(item);
|
||||
stack.pop_back();
|
||||
if (stack.size() == 0) {
|
||||
exp = BEof;
|
||||
} else if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
exp = ObjectEnd | Comma | String | Variable;
|
||||
} else {
|
||||
exp = ArrayEnd | Comma | Integer | Float | String | Bool | Variable;
|
||||
}
|
||||
break;
|
||||
case ArrayBegin:
|
||||
items.push_back(item);
|
||||
exp = ObjectBegin | ArrayBegin | ArrayEnd | Integer | Float | String | Bool | Variable;
|
||||
stack.push_back('[');
|
||||
break;
|
||||
case Comma:
|
||||
if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
exp = String | Variable;
|
||||
waitkey = true;
|
||||
} else {
|
||||
exp = ObjectBegin | ArrayBegin | Integer | Float | String | Bool | Variable;
|
||||
}
|
||||
delete item;
|
||||
break;
|
||||
case Colon:
|
||||
exp = ObjectBegin | ArrayBegin | Integer | Float | String | Bool | Variable;
|
||||
keyIndex = int(items.size()) - 1;
|
||||
waitkey = false;
|
||||
delete item;
|
||||
break;
|
||||
case Integer:
|
||||
case Float:
|
||||
case String:
|
||||
case Bool:
|
||||
case Variable:
|
||||
items.push_back(item);
|
||||
if ((ch=stack[stack.size()-1]) == '{') { // in object
|
||||
if (waitkey) {
|
||||
waitkey = false;
|
||||
exp = Colon;
|
||||
} else {
|
||||
exp = ObjectEnd | Comma;
|
||||
}
|
||||
} else {
|
||||
exp = ArrayEnd | Comma | Integer | Float | String | Bool | Variable;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// get next token from data, may modify data
|
||||
void nextToken(char* data, char**end, Token &tk) {
|
||||
char ch;
|
||||
size_t i = 0;
|
||||
|
||||
*end = NULL;
|
||||
while (data[i] == ' ') {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (data[i] == '\0') {
|
||||
tk.type = BEof;
|
||||
return;
|
||||
}
|
||||
|
||||
tk.sval = data+i;
|
||||
while ((ch=data[i++]) != '\0') {
|
||||
if (tk.type == String) {
|
||||
if (ch != '\'') {
|
||||
continue;
|
||||
} else if (isEnd(data[i])) {
|
||||
data[i-1] = '\0';
|
||||
*end = data+i;
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
return;
|
||||
} else if (tk.type == Integer || tk.type == Float) {
|
||||
if (ch>='0' && ch<='9') {
|
||||
continue;
|
||||
} else if (ch == '.') {
|
||||
tk.type = Float;
|
||||
continue;
|
||||
} else if (isEnd(ch)) {
|
||||
if (tk.type == Integer) {
|
||||
data[i-1] = '\0';
|
||||
if (Util::atoi(tk.sval, tk.lval)) {
|
||||
*end = data+i-1;
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
data[i-1] = ch;
|
||||
} else {
|
||||
char *dend;
|
||||
tk.dval = strtod(tk.sval, &dend);
|
||||
if (dend != data+i-1) {
|
||||
tk.type = Unknow;
|
||||
} else {
|
||||
*end = dend;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
return;
|
||||
} else if (tk.type == Variable) {
|
||||
if ((ch>='0' && ch<='9') || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || ch=='_') {
|
||||
continue;
|
||||
} else if (isEnd(ch)) {
|
||||
*end = data+i-1;
|
||||
} else {
|
||||
tk.type = Unknow;
|
||||
}
|
||||
return;
|
||||
} else if (ch == '{') {
|
||||
tk.type = ObjectBegin;
|
||||
break;
|
||||
} else if (ch == '}') {
|
||||
tk.type = ObjectEnd;
|
||||
break;
|
||||
} else if (ch == '[') {
|
||||
tk.type = ArrayBegin;
|
||||
break;
|
||||
} else if (ch == ']') {
|
||||
tk.type = ArrayEnd;
|
||||
break;
|
||||
} else if (ch == ',') {
|
||||
tk.type = Comma;
|
||||
break;
|
||||
} else if (ch == ':') {
|
||||
tk.type = Colon;
|
||||
break;
|
||||
} else if (ch == '\'') { // string
|
||||
tk.type = String;
|
||||
tk.sval = data+i;
|
||||
} else if (ch == '?') {
|
||||
tk.type = Variable;
|
||||
} else if (ch=='-' || ch=='+' || (ch>='0' && ch<='9')) {
|
||||
tk.type = Integer;
|
||||
tk.sval = data+i-1;
|
||||
} else if (ch == 't') { //
|
||||
if (strncmp(data+i-1, "true", 4) == 0 && isEnd(data[i+3])) {
|
||||
tk.type = Bool;
|
||||
tk.bval = true;
|
||||
*end = data+i+3;
|
||||
}
|
||||
return;
|
||||
} else if (ch == 'f') { //
|
||||
if (strncmp(data+i-1, "false", 5) == 0 && isEnd(data[i+4])) {
|
||||
tk.type = Bool;
|
||||
tk.bval = false;
|
||||
*end = data+i+4;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (tk.type != Unknow) {
|
||||
if (*end==NULL && (tk.type==String||tk.type==Float||tk.type==Integer||tk.type==Variable)) {
|
||||
fmtErr = "no end for string/integer/float/variable";
|
||||
tk.type = BEof;
|
||||
} else {
|
||||
*end = data+i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string raw;
|
||||
std::string fmtErr;
|
||||
std::string lastErr;
|
||||
std::string bstr; // for that without any variable
|
||||
char* dup; // for parse
|
||||
std::vector<const Item*> items;
|
||||
Encoder *en;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
279
util/xpack/bson_decoder.h
Executable file
279
util/xpack/bson_decoder.h
Executable file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_DECODER_H
|
||||
#define __X_PACK_BSON_DECODER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <libbson-1.0/bson.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "xdecoder.h"
|
||||
#include "bson_type.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
|
||||
class BsonNode {
|
||||
typedef XDecoder<BsonNode> decoder;
|
||||
friend class BsonDecoder;
|
||||
public:
|
||||
typedef size_t Iterator;
|
||||
|
||||
BsonNode(const bson_iter_t* iter = NULL):it(iter),inited(false) {
|
||||
if (NULL != it) {
|
||||
type = bson_iter_type(it);
|
||||
}
|
||||
}
|
||||
|
||||
inline static const char * Name() {
|
||||
return "bson";
|
||||
}
|
||||
operator bool () const {
|
||||
return it != NULL;
|
||||
}
|
||||
bool IsNull() const {
|
||||
return NULL!=it && BSON_TYPE_NULL==bson_iter_type(it);
|
||||
}
|
||||
BsonNode Find(decoder&de, const char*key, const Extend *ext) {
|
||||
(void)de;
|
||||
(void)ext;
|
||||
|
||||
if (!inited) {
|
||||
this->init();
|
||||
}
|
||||
|
||||
if (BSON_TYPE_DOCUMENT != type) {
|
||||
de.decode_exception("not document", NULL);
|
||||
}
|
||||
|
||||
node_index::iterator iter = _childs_index.find(key);
|
||||
if (iter != _childs_index.end()) {
|
||||
return BsonNode(&_childs[iter->second]);
|
||||
} else {
|
||||
return BsonNode();
|
||||
}
|
||||
}
|
||||
size_t Size(decoder&de) {
|
||||
(void)de;
|
||||
if (!inited) {
|
||||
this->init();
|
||||
}
|
||||
|
||||
if (BSON_TYPE_ARRAY == type) {
|
||||
return _childs.size();
|
||||
} else {
|
||||
de.decode_exception("not array", NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
BsonNode At(size_t index) const { // no exception
|
||||
return BsonNode(&(_childs[index]));
|
||||
}
|
||||
BsonNode Next(decoder&de, BsonNode&p, Iterator&iter, std::string&key) {
|
||||
(void)de;
|
||||
if (!p.inited) {
|
||||
p.init();
|
||||
}
|
||||
if (BSON_TYPE_DOCUMENT != p.type) {
|
||||
de.decode_exception("not document", NULL);
|
||||
}
|
||||
|
||||
if (it != p.it) {
|
||||
++iter;
|
||||
} else {
|
||||
iter = 0;
|
||||
}
|
||||
|
||||
if (iter != p._childs.size()) {
|
||||
bson_iter_t *t = &p._childs[iter];
|
||||
key = bson_iter_key(t);
|
||||
return BsonNode(t);
|
||||
}
|
||||
|
||||
return BsonNode();
|
||||
}
|
||||
|
||||
bool Get(decoder&de, std::string&val, const Extend*ext) {
|
||||
(void)ext;
|
||||
|
||||
if (BSON_TYPE_UTF8 == type) {
|
||||
uint32_t length;
|
||||
const char* data = bson_iter_utf8(it, &length);
|
||||
if (NULL != data) {
|
||||
val = std::string(data, length);
|
||||
}
|
||||
} else if (BSON_TYPE_NULL != type) {
|
||||
de.decode_exception("not string", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Get(decoder&de, bool &val, const Extend*ext) {
|
||||
(void)de;
|
||||
(void)ext;
|
||||
val = bson_iter_as_bool(it);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)de;
|
||||
(void)ext;
|
||||
val = (T)bson_iter_as_int64(it);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)de;
|
||||
(void)ext;
|
||||
val = (T)bson_iter_double(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*std::string json() const {
|
||||
if (NULL == _data) {
|
||||
return "";
|
||||
}
|
||||
size_t length=BSON_UINT32_TO_LE(*(int32_t*)_data);
|
||||
bson_t b; // local is ok
|
||||
bson_init_static(&b, _data, length);
|
||||
|
||||
size_t s;
|
||||
char *jstr = bson_as_json(&b, &s);
|
||||
if (jstr) {
|
||||
std::string j(jstr);
|
||||
bson_free(jstr);
|
||||
return j;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}*/
|
||||
|
||||
// bson type
|
||||
bool decode_type_spec(bson_oid_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
const bson_oid_t *t = bson_iter_oid(it);
|
||||
if (t != NULL) {
|
||||
bson_oid_init_from_data(&val, t->bytes);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool decode_type_spec(bson_date_time_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
val.ts = bson_iter_date_time(it);
|
||||
return true;
|
||||
}
|
||||
bool decode_type_spec(bson_timestamp_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_iter_timestamp(it, &val.timestamp, &val.increment);
|
||||
return true;
|
||||
}
|
||||
bool decode_type_spec(bson_decimal128_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_iter_decimal128(it, &val);
|
||||
}
|
||||
bool decode_type_spec(bson_regex_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
const char *options = NULL;
|
||||
const char *regex = bson_iter_regex(it, &options);
|
||||
if (NULL != regex) {
|
||||
val.pattern = regex;
|
||||
}
|
||||
if (NULL != options) {
|
||||
val.options = options;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool decode_type_spec(bson_binary_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
uint32_t len = 0;
|
||||
const uint8_t *data = NULL;
|
||||
bson_iter_binary(it, &val.subType, &len, &data);
|
||||
if (data != NULL && len > 0) {
|
||||
val.data = std::string((const char*)data, size_t(len));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
typedef std::map<const char*, size_t, cmp_str> node_index; // index of _childs
|
||||
|
||||
// get object or array info
|
||||
void init(bool top = false) {
|
||||
inited = true;
|
||||
|
||||
bson_iter_t sub;
|
||||
if (NULL != it) {
|
||||
if (top) {
|
||||
type = BSON_TYPE_DOCUMENT;
|
||||
memcpy((void*)&sub, (void*)it, sizeof(sub));
|
||||
} else if (!bson_iter_recurse(it, &sub)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
while (bson_iter_next(&sub)) {
|
||||
_childs.push_back(sub);
|
||||
if (type == BSON_TYPE_DOCUMENT) {
|
||||
_childs_index[bson_iter_key(&sub)] = i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bson_iter_t* it;
|
||||
bson_type_t type;
|
||||
bool inited;
|
||||
std::vector<bson_iter_t> _childs; // childs
|
||||
node_index _childs_index;
|
||||
};
|
||||
|
||||
|
||||
class BsonDecoder {
|
||||
public:
|
||||
// if length==0, length will get from data
|
||||
template <class T>
|
||||
bool decode(const uint8_t*data, size_t length, T&val) {
|
||||
length = (length>0)?length:BSON_UINT32_TO_LE(*(int32_t*)data);
|
||||
|
||||
bson_t b;
|
||||
bson_iter_t it;
|
||||
bson_init_static(&b, data, length);
|
||||
bson_iter_init(&it, &b);
|
||||
|
||||
BsonNode node(&it);
|
||||
node.init(true);
|
||||
return XDecoder<BsonNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool decode(const std::string&data, T&val) {
|
||||
return decode((const uint8_t*)data.data(), data.length(), val);
|
||||
}
|
||||
};
|
||||
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_oid_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_date_time_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_timestamp_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_decimal128_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_binary_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonNode, bson_regex_t> {static bool const value = true;};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
246
util/xpack/bson_encoder.h
Executable file
246
util/xpack/bson_encoder.h
Executable file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_BSON_ENCODER_H
|
||||
#define __X_PACK_BSON_ENCODER_H
|
||||
|
||||
#include <libbson-1.0/bson.h>
|
||||
|
||||
#include "xpack/util.h"
|
||||
#include "xpack/xencoder.h"
|
||||
#include "bson_type.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class BsonWriter: private noncopyable {
|
||||
friend class BsonBuilder;
|
||||
struct Node {
|
||||
const char *key;
|
||||
Node *parent;
|
||||
bson_t data;
|
||||
|
||||
Node(const char *_key = NULL, Node *_parent=NULL):key(_key), parent(_parent) {
|
||||
if (NULL == parent) {
|
||||
bson_init(&data);
|
||||
}
|
||||
}
|
||||
~Node() {
|
||||
if (NULL == parent) {
|
||||
bson_destroy(&data);
|
||||
}
|
||||
}
|
||||
};
|
||||
friend class XEncoder<BsonWriter>;
|
||||
friend class BsonEncoder;
|
||||
const static bool support_null = true;
|
||||
public:
|
||||
BsonWriter() {
|
||||
cur = new Node(NULL, NULL);
|
||||
nodes.push_back(cur);
|
||||
}
|
||||
|
||||
~BsonWriter() {
|
||||
std::list<Node*>::iterator it;
|
||||
for (it = nodes.begin(); it!=nodes.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
private:
|
||||
inline static const char *Name() {
|
||||
return "bson";
|
||||
}
|
||||
inline const char *IndexKey(size_t index) {
|
||||
if (index > indexStr.size()+1) {
|
||||
std::string s = Util::itoa(index);
|
||||
errCase.push_back(s);
|
||||
return errCase.back().c_str();
|
||||
}
|
||||
if (index >= indexStr.size()) {
|
||||
std::string s = Util::itoa(index);
|
||||
indexStr.push_back(s);
|
||||
}
|
||||
return indexStr[index].c_str();
|
||||
}
|
||||
// return bson binary data
|
||||
std::string String() const {
|
||||
return std::string((const char*)bson_get_data(&cur->data), cur->data.len);
|
||||
}
|
||||
// return json format string
|
||||
std::string Json() const {
|
||||
size_t len;
|
||||
char *jstr = bson_as_json(&cur->data, &len);
|
||||
std::string ret(jstr);
|
||||
bson_free(jstr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ArrayBegin(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (key != NULL) {
|
||||
Node *tmp = new Node(key, cur);
|
||||
nodes.push_back(tmp);
|
||||
|
||||
bson_append_array_begin(&cur->data, key, strlen(key), &tmp->data);
|
||||
cur = tmp;
|
||||
}
|
||||
}
|
||||
void ArrayEnd(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (NULL != key) {
|
||||
bson_append_array_end(&cur->parent->data, &cur->data);
|
||||
cur = cur->parent; // do not pop and delete
|
||||
}
|
||||
}
|
||||
void ObjectBegin(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (key != NULL) {
|
||||
Node *tmp = new Node(key, cur);
|
||||
nodes.push_back(tmp);
|
||||
|
||||
bson_append_document_begin(&cur->data, key, strlen(key), &tmp->data);
|
||||
cur = tmp;
|
||||
}
|
||||
}
|
||||
void ObjectEnd(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (NULL != key) { // in case of inherit, object key is NULL
|
||||
bson_append_document_end(&cur->parent->data, &cur->data);
|
||||
cur = cur->parent; // do not pop and delete
|
||||
}
|
||||
}
|
||||
bool WriteNull(const char*key, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_null(&cur->data, key, strlen(key));
|
||||
return true;
|
||||
}
|
||||
bool encode_bool(const char*key, const bool &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_bool(&cur->data, key, strlen(key), val);
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const char*val, size_t length, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_utf8(&cur->data, key, strlen(key), val, length);
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const std::string& val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_utf8(&cur->data, key, strlen(key), (const char*)val.data(), val.length());
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const char* val, const Extend *ext) {
|
||||
(void)ext;
|
||||
if (NULL != val) {
|
||||
bson_append_utf8(&cur->data, key, strlen(key), val, strlen(val));
|
||||
} else {
|
||||
bson_append_utf8(&cur->data, key, strlen(key), "", 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define X_PACK_BSON_ENCODE_NUMBER(vtype, ftype, ctype) \
|
||||
inline bool encode_number(const char*key, const vtype&val, const Extend*ext) {\
|
||||
(void)ext;\
|
||||
bson_append_##ftype(&cur->data, key, strlen(key), (vtype)val);\
|
||||
return true; \
|
||||
}
|
||||
X_PACK_BSON_ENCODE_NUMBER(char, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(signed char, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned char, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(short, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned short, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(int, int32, int32_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned int, int32, int32_t)
|
||||
|
||||
X_PACK_BSON_ENCODE_NUMBER(long, int64, int64_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned long, int64, int64_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(long long, int64, int64_t)
|
||||
X_PACK_BSON_ENCODE_NUMBER(unsigned long long, int64, int64_t)
|
||||
|
||||
X_PACK_BSON_ENCODE_NUMBER(float, double, double)
|
||||
X_PACK_BSON_ENCODE_NUMBER(double, double, double)
|
||||
X_PACK_BSON_ENCODE_NUMBER(long double, double, double)
|
||||
|
||||
// bson types
|
||||
bool encode_type_spec(const char*key, const bson_oid_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_oid(&cur->data, key, strlen(key), &val);
|
||||
return true;
|
||||
}
|
||||
bool encode_type_spec(const char*key, const bson_date_time_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_date_time(&cur->data, key, strlen(key), val.ts);
|
||||
return true;
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_timestamp_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bson_append_timestamp(&cur->data, key, strlen(key), val.timestamp, val.increment);
|
||||
return true;
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_decimal128_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_append_decimal128(&cur->data, key, strlen(key), &val);
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_regex_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_append_regex(&cur->data, key, strlen(key), val.pattern.c_str(), val.options.c_str());
|
||||
}
|
||||
bool encode_type_spec(const char *key, const bson_binary_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return bson_append_binary(&cur->data, key, strlen(key), val.subType, (const uint8_t*)val.data.data(), val.data.length());
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> indexStr;
|
||||
std::list<std::string> errCase;
|
||||
std::list<Node*> nodes;
|
||||
Node *cur;
|
||||
};
|
||||
|
||||
class BsonEncoder {
|
||||
public:
|
||||
BsonEncoder() {
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode(const T&val) {
|
||||
BsonWriter wr;
|
||||
XEncoder<BsonWriter> en(wr);
|
||||
en.encode(NULL, val, NULL);
|
||||
return wr.String();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode_as_json(const T&val) {
|
||||
BsonWriter wr;
|
||||
XEncoder<BsonWriter> en(wr);
|
||||
en.encode(NULL, val, NULL);
|
||||
return wr.Json();
|
||||
}
|
||||
};
|
||||
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_oid_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_date_time_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_timestamp_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_decimal128_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_binary_t> {static bool const value = true;};
|
||||
template<>struct is_xpack_type_spec<BsonWriter, bson_regex_t> {static bool const value = true;};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
450
util/xpack/bson_type.h
Executable file
450
util/xpack/bson_type.h
Executable file
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_BSON_TYPE_H
|
||||
#define __X_PACK_BSON_TYPE_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libbson-1.0/bson.h>
|
||||
|
||||
#include "xencoder.h"
|
||||
#include "xdecoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
/*
|
||||
// define in this file
|
||||
bson_date_time_t
|
||||
bson_timestamp_t
|
||||
bson_binary_t
|
||||
bson_regex_t
|
||||
|
||||
// define in bson.h
|
||||
bson_oid_t
|
||||
bson_decimal128_t
|
||||
*/
|
||||
|
||||
// define in global namespace for consistency with bson
|
||||
struct bson_timestamp_t {
|
||||
uint32_t timestamp;
|
||||
uint32_t increment;
|
||||
bson_timestamp_t(const uint32_t&t=0, const uint32_t&i=0):timestamp(t),increment(i){}
|
||||
XPACK(A(timestamp, "t", increment, "i"));
|
||||
};
|
||||
struct bson_regex_t {
|
||||
std::string pattern; // libbson not escape string, this should be a bug
|
||||
std::string options;
|
||||
// ver==1 {"$regularExpression": {pattern: <string>, "options": <string>"}}
|
||||
// ver==2 {"$regex: <string>, $options: <string>"}
|
||||
int ver; // ver==1
|
||||
bson_regex_t():ver(2){}
|
||||
};
|
||||
struct bson_date_time_t {
|
||||
int64_t ts; // milliseconds
|
||||
bson_date_time_t(const int64_t&t=0):ts(t){}
|
||||
operator int64_t() const {return ts;}
|
||||
|
||||
// parse rfc3339 time format(milliseconds). C++ doesn't even have a full-featured standard time library T_T
|
||||
// "2000-01-01T01:01:01[.001]Z[07:00]" string should ends with \0
|
||||
bool parse_rfc3339(const char buf[]) {
|
||||
struct tm tm;
|
||||
memset((void*)&tm, 0, sizeof(tm));
|
||||
|
||||
const char *end = strptime(buf, "%Y-%m-%dT%H:%M:%S", &tm);
|
||||
if (end == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int msec = 0;
|
||||
int offset = 0;
|
||||
try {
|
||||
size_t pos;
|
||||
if (*end == '.') {
|
||||
msec = std::stoi(end+1, &pos);
|
||||
if (pos==0 || pos > 3) {
|
||||
return false;
|
||||
}
|
||||
end += pos+1;
|
||||
}
|
||||
if (*end != 'Z') {
|
||||
pos = 0;
|
||||
int hour = std::stoi(end, &pos);
|
||||
if (pos == 0 || pos > 3) {
|
||||
return false;
|
||||
}
|
||||
end += pos;
|
||||
if (*end != ':') {
|
||||
return false;
|
||||
}
|
||||
int min = std::stoi(end+1, &pos);
|
||||
if (hour > 0) {
|
||||
offset = hour*3600 + min*60;
|
||||
} else {
|
||||
offset = -(-hour*3600 + min*60);
|
||||
}
|
||||
} else {
|
||||
++end;
|
||||
if (*end != '\0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch(...) {
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t tmp = mktime(&tm);
|
||||
ts = tmp*1000 + msec - offset - timezone*1000;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct bson_binary_t {
|
||||
std::string data; // std::string is more general, so don't use std::basic_string<uint8_t>
|
||||
bson_subtype_t subType;
|
||||
|
||||
inline static const char *b64() {
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
}
|
||||
|
||||
// b64_ntop and b64_pton maybe should move to a public place
|
||||
static void b64_ntop(const uint8_t *bin, size_t size, std::string&out) {
|
||||
const char *b = b64();
|
||||
|
||||
out.reserve((size+2)/3*4);
|
||||
size_t n = size/3*3;
|
||||
size_t i;
|
||||
for (i=0; i<n; i+=3) {
|
||||
out.push_back(b[bin[i]>>2]);
|
||||
out.push_back(b[((bin[i]&0x3)<<4) | (bin[i+1]>>4)]);
|
||||
out.push_back(b[((bin[i+1]&0xf)<<2) | (bin[i+2]>>6)]);
|
||||
out.push_back(b[bin[i+2]&0x3f]);
|
||||
}
|
||||
size_t left = size%3;
|
||||
if (left == 1) {
|
||||
out.push_back(b[bin[i]>>2]);
|
||||
out.push_back(b[(bin[i]&0x3)<<4]);
|
||||
out.push_back('=');
|
||||
out.push_back('=');
|
||||
} else if (left == 2) {
|
||||
out.push_back(b[bin[i]>>2]);
|
||||
out.push_back(b[((bin[i]&0x3)<<4) | (bin[i+1]>>4)]);
|
||||
out.push_back(b[(bin[i+1]&0xf)<<2]);
|
||||
out.push_back('=');
|
||||
}
|
||||
}
|
||||
static bool b64_pton(const std::string&in, std::string&out) {
|
||||
static uint8_t bmap[256] = {0};
|
||||
if (bmap[255] == 0) { // init bmap, thread safe
|
||||
for (size_t i=0; i<255; i++) bmap[i] = 0xff;
|
||||
const char *p = b64();
|
||||
for (uint8_t i=0; p[i]!='\0'; ++i) bmap[(int)p[i]] = i;
|
||||
bmap[255] = 0xff;
|
||||
}
|
||||
|
||||
size_t size = in.length();
|
||||
if (size==0 || 0 != (size&0x3)) {
|
||||
return false;
|
||||
}
|
||||
out.reserve((size+3)/4*3);
|
||||
|
||||
const char *data = in.data();
|
||||
for (size_t i=0; i<size; i+=4) {
|
||||
uint8_t i1 = bmap[(uint8_t)data[i]];
|
||||
uint8_t i2 = bmap[(uint8_t)data[i+1]];
|
||||
uint8_t i3 = bmap[(uint8_t)data[i+2]];
|
||||
uint8_t i4 = bmap[(uint8_t)data[i+3]];
|
||||
if (i1!=0xff && i2!=0xff) {
|
||||
out.push_back((char)((i1<<2) | (i2>>4)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i3 != 0xff) {
|
||||
out.push_back((char)((i2<<4) | (i3>>2)));
|
||||
} else if (data[i+2]=='=' && data[i+3]=='=' && i+4==size) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (i4 != 0xff) {
|
||||
out.push_back((char)((i3<<6) | i4));
|
||||
} else if (data[i+3]=='=' && i+4==size) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace xpack {
|
||||
|
||||
// bson type to json
|
||||
// ref https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#conversion-table
|
||||
// Relaxed Extended JSON Format Only
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ObjectId ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$oid":"xxxxx"}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_oid_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_oid_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
char buf[25];
|
||||
bool ret = de.decode("$oid", buf, NULL);
|
||||
if (ret) {
|
||||
bson_oid_init_from_string(&val, buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_oid_t &val, const Extend *ext) {
|
||||
char buf[25];
|
||||
bson_oid_to_string(&val, buf);
|
||||
en.ObjectBegin(key, ext);
|
||||
en.encode("$oid", buf, NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ date time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
// {"$date": 12345}
|
||||
// {"$date":"2006-01-02T15:04:05Z"}
|
||||
// {"$date":{"$numberLong":"123456"}}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_date_time_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_date_time_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
static const char *dkey = "$date";
|
||||
|
||||
bool ret;
|
||||
try {
|
||||
ret = de.decode(dkey, val.ts, NULL);
|
||||
return ret;
|
||||
} catch (...){}
|
||||
|
||||
char buf[25];
|
||||
try {
|
||||
ret = de.decode(dkey, buf, NULL);
|
||||
if (ret) {
|
||||
ret = val.parse_rfc3339(buf);
|
||||
}
|
||||
return ret;
|
||||
} catch (...) {}
|
||||
|
||||
try {
|
||||
ret = de.decode("$numberLong", buf, NULL);
|
||||
if (ret) {
|
||||
ret = Util::atoi(buf, val.ts);
|
||||
}
|
||||
return ret;
|
||||
} catch (...) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_date_time_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
if (val.ts >= 0) {
|
||||
char buf[32];
|
||||
int msecs = int(val.ts % 1000);
|
||||
time_t secs = (time_t)(val.ts/1000);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
struct tm posix_date;
|
||||
size_t sz = strftime(buf, sizeof buf, "%FT%T", gmtime_r(&secs, &posix_date));
|
||||
#else
|
||||
size_t sz = strftime(buf, sizeof buf, "%FT%T", gmtime(&secs));
|
||||
#endif
|
||||
|
||||
if (msecs > 0) {
|
||||
sprintf(&buf[sz], ".%03dZ", msecs);
|
||||
} else {
|
||||
strcpy(&buf[sz], "Z");
|
||||
}
|
||||
en.encode("$date", buf, NULL);
|
||||
} else { // key:{"$date":{"$numberLong":ts}} ts use string not int
|
||||
en.ObjectBegin("$date", NULL);
|
||||
en.encode("$numberLong", Util::itoa(val.ts), NULL);
|
||||
en.ObjectEnd("$date", NULL);
|
||||
}
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ timestamp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$timestamp":{"t":xxx, "i":xxx}}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_timestamp_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_timestamp_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
bool ret = de.decode_struct("$timestamp", val, NULL);
|
||||
return ret;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_timestamp_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
en.encode_struct("$timestamp", val, NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ numberDecimal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$numberDecimal":"123.4"}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_decimal128_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_decimal128_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
char buf[BSON_DECIMAL128_STRING];
|
||||
bool ret = de.decode("$numberDecimal", buf, NULL);
|
||||
if (ret) {
|
||||
bson_decimal128_from_string(buf, &val);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_decimal128_t &val, const Extend *ext) {
|
||||
char buf[BSON_DECIMAL128_STRING];
|
||||
bson_decimal128_to_string(&val, buf);
|
||||
en.ObjectBegin(key, ext);
|
||||
en.encode("$numberDecimal", buf, NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ binary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
// {"$binary":{"base64":"aGVsbG8=","subType":"80"}}
|
||||
// {"$binary":"aGVsbG8=", "$type":"80"}
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_binary_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_binary_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
try {
|
||||
std::string subType;
|
||||
std::string data;
|
||||
bool ret1;
|
||||
bool ret2;
|
||||
|
||||
Decoder st = de.Find("$type", NULL);
|
||||
if (!st) {
|
||||
Decoder bd = de.Find("$binary", NULL);
|
||||
if (!bd) {
|
||||
return false;
|
||||
}
|
||||
ret1 = bd.decode("subType", subType, NULL);
|
||||
ret2 = bd.decode("base64", data, NULL);
|
||||
} else {
|
||||
ret1 = st.decode(subType, NULL);
|
||||
ret2 = de.decode("$binary", data, NULL);
|
||||
}
|
||||
|
||||
if (ret1 && (subType.length()==1 || subType.length()==2)) {
|
||||
int st = 0;
|
||||
for (size_t i=0; i<subType.length(); ++i) {
|
||||
int tmp = (int)(subType[i]);
|
||||
if (tmp>='0' && tmp<='9') {
|
||||
tmp -= '0';
|
||||
} else if (tmp>='a' && tmp<='f') {
|
||||
tmp = 10 + tmp-'a';
|
||||
} else if (tmp>='A' && tmp<='F') {
|
||||
tmp = 10 + tmp-'A';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
st = (st<<4) + tmp;
|
||||
}
|
||||
val.subType = (bson_subtype_t)st;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ret2) {
|
||||
ret2 = bson_binary_t::b64_pton(data, val.data);
|
||||
}
|
||||
return ret2;
|
||||
} catch (...){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_binary_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
en.ObjectBegin("$binary", NULL);
|
||||
|
||||
std::string b64;
|
||||
bson_binary_t::b64_ntop((const uint8_t*)val.data.data(), val.data.length(), b64);
|
||||
en.encode("base64", b64, NULL);
|
||||
|
||||
std::stringstream ss;
|
||||
ss<<std::hex<<val.subType;
|
||||
en.encode("subType", ss.str(), NULL);
|
||||
|
||||
en.ObjectEnd("$binary", NULL);
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ regex ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
|
||||
template<>
|
||||
struct is_xpack_xtype<bson_regex_t> {static bool const value = true;};
|
||||
template<class Decoder>
|
||||
bool xpack_xtype_decode(Decoder &de, bson_regex_t &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
Decoder v1 = de.Find("$regularExpression", NULL);
|
||||
try {
|
||||
if (v1) {
|
||||
v1.decode("pattern", val.pattern, NULL);
|
||||
v1.decode("options", val.options, NULL);
|
||||
val.ver = 1;
|
||||
} else {
|
||||
de.decode("$regex", val.pattern, NULL);
|
||||
de.decode("$options", val.options, NULL);
|
||||
val.ver = 2;
|
||||
}
|
||||
} catch(...){}
|
||||
return true;
|
||||
}
|
||||
template<class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char*key, const bson_regex_t &val, const Extend *ext) {
|
||||
en.ObjectBegin(key, ext);
|
||||
if (val.ver == 1) {
|
||||
en.ObjectBegin("$regularExpression", NULL);
|
||||
en.encode("pattern", val.pattern, NULL);
|
||||
en.encode("options", val.options, NULL);
|
||||
en.ObjectEnd("$regularExpression", NULL);
|
||||
} else {
|
||||
en.encode("$regex", val.pattern, NULL);
|
||||
en.encode("$options", val.options, NULL);
|
||||
}
|
||||
en.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
25
util/xpack/config.h
Executable file
25
util/xpack/config.h
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_CONFIG_H
|
||||
#define __X_PACK_CONFIG_H
|
||||
|
||||
// support qt
|
||||
//#define XPACK_SUPPORT_QT
|
||||
|
||||
|
||||
#endif
|
||||
27
util/xpack/example/alias.cpp
Executable file
27
util/xpack/example/alias.cpp
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(A(uid, "id xml:xid"), O(name)); // xml use 'xid' and others use 'id'
|
||||
};
|
||||
|
||||
int main() {
|
||||
Test t;
|
||||
string json="{\"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.uid<<endl;
|
||||
|
||||
string xstr = xpack::xml::encode(t, "root");
|
||||
cout<<xstr<<endl;
|
||||
Test t1;
|
||||
xpack::xml::decode(xstr, t1);
|
||||
cout<<t1.uid<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
util/xpack/example/bitfield.cpp
Executable file
23
util/xpack/example/bitfield.cpp
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
short ver:8;
|
||||
short len:8;
|
||||
string name;
|
||||
XPACK(B(F(0), ver, len), O(name));
|
||||
};
|
||||
|
||||
int main() {
|
||||
Test t;
|
||||
string json="{\"ver\":4, \"len\":20, \"name\":\"IPv4\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.ver<<endl;
|
||||
cout<<t.len<<endl;
|
||||
cout<<xpack::xml::encode(t, "root")<<endl;
|
||||
return 0;
|
||||
}
|
||||
40
util/xpack/example/char_array.cpp
Executable file
40
util/xpack/example/char_array.cpp
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Test {
|
||||
char name[64];
|
||||
char email[64];
|
||||
XPACK(O(name, email));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
Test t;
|
||||
string json="{\"name\":\"Pony\", \"email\":\"pony@xpack.com\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<t.name<<endl;
|
||||
cout<<t.email<<endl;
|
||||
return 0;
|
||||
}
|
||||
66
util/xpack/example/custom.cpp
Executable file
66
util/xpack/example/custom.cpp
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Test {
|
||||
unsigned int uid;
|
||||
string name;
|
||||
XPACK(C(hexint, F(0), uid), O(name));
|
||||
};
|
||||
|
||||
namespace xpack {
|
||||
|
||||
template <class Decoder>
|
||||
bool hexint_decode(Decoder&de, Test&t, const char *name, unsigned int&data, const xpack::Extend *ext) {
|
||||
(void)t;
|
||||
string raw;
|
||||
bool ret = de.decode(name, raw, ext);
|
||||
if (ret) {
|
||||
sscanf(raw.c_str(), "%x", &data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class Encoder>
|
||||
bool hexint_encode(Encoder&en, const Test&t, const char *name, const unsigned &data, const xpack::Extend *ext) {
|
||||
(void)t;
|
||||
char buf[64];
|
||||
sprintf(buf, "%x", data);
|
||||
bool ret = en.encode(name, buf, ext);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
Test t;
|
||||
t.uid = 127;
|
||||
t.name = "PonyJack";
|
||||
|
||||
string str = xpack::json::encode(t);
|
||||
cout<<str<<endl;
|
||||
|
||||
Test n;
|
||||
xpack::json::decode(str, t);
|
||||
cout<<t.uid<<endl;
|
||||
return 0;
|
||||
}
|
||||
45
util/xpack/example/encoder.cpp
Executable file
45
util/xpack/example/encoder.cpp
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
vector<int> vi(3);
|
||||
vi[0] = 1;
|
||||
vi[1] = 2;
|
||||
vi[2] = 3;
|
||||
|
||||
xpack::JsonWriter jw;
|
||||
xpack::XEncoder<xpack::JsonWriter> je(jw);
|
||||
|
||||
xpack::XmlWriter xw;
|
||||
xpack::XEncoder<xpack::XmlWriter> xe(xw);
|
||||
|
||||
je.ob(NULL).add("vv", vi).add("i",10).add("s","hello").oe();
|
||||
xe.ob("root").add("vv", vi).add("i",10).add("s","hello").oe();
|
||||
|
||||
cout<<je.String()<<endl;
|
||||
cout<<xe.String()<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
58
util/xpack/example/enum.cpp
Executable file
58
util/xpack/example/enum.cpp
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum Enum {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
enum class Enum1 {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
enum class Enum2:int64_t {
|
||||
X = 0,
|
||||
Y = 1,
|
||||
Z = 2,
|
||||
};
|
||||
|
||||
struct Test {
|
||||
string name;
|
||||
Enum e;
|
||||
Enum1 e1;
|
||||
Enum2 e2;
|
||||
XPACK(O(name), E(F(0), e), O(e1, e2));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
Test t;
|
||||
string json="{\"name\":\"IPv4\", \"e\":1, \"e1\":2, \"e2\":2}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<xpack::json::encode(t)<<endl;
|
||||
return 0;
|
||||
}
|
||||
69
util/xpack/example/inherit.cpp
Executable file
69
util/xpack/example/inherit.cpp
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct P1 {
|
||||
string mail;
|
||||
XPACK(O(mail));
|
||||
};
|
||||
|
||||
struct P2 {
|
||||
long version;
|
||||
XPACK(O(version));
|
||||
};
|
||||
|
||||
struct Test:public P1, public P2 {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(I(P1, P2), A(uid, "id"), O(name));
|
||||
};
|
||||
|
||||
struct Pa {
|
||||
string mail;
|
||||
XPACK(O(mail));
|
||||
};
|
||||
|
||||
struct Pb: public Pa {
|
||||
long version;
|
||||
XPACK(I(Pa), O(version));
|
||||
};
|
||||
|
||||
struct Pc:public Pb {
|
||||
long uid;
|
||||
string name;
|
||||
XPACK(I(Pb), A(uid, "id"), O(name));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
Test t;
|
||||
string json="{\"mail\":\"pony@xpack.com\", \"version\":2019, \"id\":123, \"name\":\"Pony\"}";
|
||||
|
||||
xpack::json::decode(json, t);
|
||||
cout<<xpack::json::encode(t)<<endl;
|
||||
|
||||
Pc p;
|
||||
xpack::json::decode(json, p);
|
||||
cout<<xpack::json::encode(p)<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
73
util/xpack/example/json-data.cpp
Executable file
73
util/xpack/example/json-data.cpp
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Example {
|
||||
string type;
|
||||
xpack::JsonData data;
|
||||
XPACK(O(type, data));
|
||||
};
|
||||
|
||||
struct Range {
|
||||
int min;
|
||||
int max;
|
||||
XPACK(O(min, max));
|
||||
};
|
||||
|
||||
struct User {
|
||||
int id;
|
||||
string name;
|
||||
XPACK(O(id, name));
|
||||
};
|
||||
|
||||
static void test(const std::string &data) {
|
||||
Example e;
|
||||
xpack::json::decode(data, e);
|
||||
if (e.type == "range") {
|
||||
Range r;
|
||||
e.data.Get(r);
|
||||
cout<<"min in r:"<<r.min<<endl;
|
||||
cout<<"max in r:"<<r.max<<endl;
|
||||
|
||||
cout<<"min:"<<e.data["min"].Get<int>()<<endl;
|
||||
cout<<"max:"<<e.data["max"].Get<int>()<<endl;
|
||||
} else if (e.type == "user") {
|
||||
cout<<"id:"<<e.data["id"].Get<int>()<<endl;
|
||||
cout<<"name:"<<e.data["name"].Get<std::string>()<<endl;
|
||||
} else {
|
||||
cout<<"unknow type"<<endl;
|
||||
}
|
||||
cout<<"re encode:"<<xpack::json::encode(e)<<endl;
|
||||
cout<<"data encode:"<<xpack::json::encode(e.data)<<endl;
|
||||
cout<<"data dir encode:"<<e.data.String()<<endl;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
string s1 = "{\"type\":\"range\", \"data\":{\"min\":12, \"max\":22}}";
|
||||
string s2 = "{\"type\":\"user\", \"data\":{\"id\":123, \"name\":\"xpack\"}}";
|
||||
test(s1);
|
||||
test(s2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
util/xpack/example/makefile
Executable file
36
util/xpack/example/makefile
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
ifeq ($(GPP),)
|
||||
GPP=g++
|
||||
endif
|
||||
|
||||
SRC=$(wildcard *.cpp)
|
||||
TAR=$(basename $(SRC))
|
||||
|
||||
ifeq ($(c11),off)
|
||||
NEEDC11=sharedptr
|
||||
TAR:=$(filter-out $(NEEDC11),$(TAR))
|
||||
else
|
||||
CXXFLAG=-std=c++11
|
||||
endif
|
||||
|
||||
%:%.cpp
|
||||
$(GPP) -o $@ -g $< -Wall -Wextra -I ../.. ${CXXFLAG}
|
||||
@echo ============ run $@ ================
|
||||
@./$@
|
||||
@-rm $@
|
||||
@-rm -rf $@.dSYM
|
||||
|
||||
tar:$(TAR)
|
||||
@echo -------test done-------
|
||||
|
||||
mysql:mysql.cpp
|
||||
$(GPP) -o $@ -g $< -lmysqlclient -I ../..
|
||||
|
||||
sqlite:sqlite.cpp
|
||||
$(GPP) -o $@ -g $< -lsqlite -I ../..
|
||||
|
||||
yaml:yaml.cpp
|
||||
$(GPP) -o $@ -g $< -Wall -Wextra -I ../.. -I ../../yaml-cpp/include ../../yaml-cpp/build/libyaml-cpp.a -std=c++11
|
||||
@echo ============ run $@ ================
|
||||
@./$@
|
||||
@-rm $@
|
||||
@-rm -rf $@.dSYM
|
||||
19
util/xpack/example/msvc.make
Executable file
19
util/xpack/example/msvc.make
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
MAKEFLAGS += --no-builtin-rules
|
||||
MAKEFLAGS += --no-builtin-variables
|
||||
SRC=$(wildcard *.cpp)
|
||||
TAR=$(SRC:.cpp=)
|
||||
|
||||
NEEDLIB=mysql sqlite yaml
|
||||
TAR:=$(filter-out $(NEEDLIB),$(TAR))
|
||||
|
||||
%:%.cpp
|
||||
cl /Fe:${CURDIR}/$@.exe /nologo /wd4819 $< /EHsc -I ../..
|
||||
@echo ============ run $@.exe ================
|
||||
@$@.exe
|
||||
@del $@.exe $@.obj
|
||||
|
||||
tar:$(TAR)
|
||||
@echo -------test done-------
|
||||
|
||||
clean:
|
||||
@-del *.obj *.exe
|
||||
70
util/xpack/example/my_decoder.cpp
Executable file
70
util/xpack/example/my_decoder.cpp
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
// assign value by name
|
||||
class AssignDecoder {
|
||||
public:
|
||||
AssignDecoder(const std::vector<std::string>&vs, const unsigned char *src, unsigned char *dst) {
|
||||
for (size_t i=0; i<vs.size(); ++i) {
|
||||
fields.insert(vs[i]);
|
||||
}
|
||||
this->src = src;
|
||||
this->dst = dst;
|
||||
}
|
||||
|
||||
// decoder need implemetion decode function
|
||||
template<class T>
|
||||
bool decode(const char *key, T&val, const xpack::Extend *ext) {
|
||||
(void)ext;
|
||||
// set value by offset
|
||||
if (fields.end() != fields.find(key)) {
|
||||
unsigned int offset = (unsigned int)((unsigned char*)&val - dst);
|
||||
val = *((T*)(src+offset));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::set<std::string> fields;
|
||||
const unsigned char *src;
|
||||
unsigned char *dst;
|
||||
};
|
||||
|
||||
// SetFields<T>(src, dst, "a,b") means dst.a = src.a; dst.b = src.b;
|
||||
template <class T>
|
||||
void SetFields(const T&src, T&dst, const std::string&fields) {
|
||||
std::vector<std::string> vs;
|
||||
xpack::Util::split(vs, fields, ',');
|
||||
if (vs.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
AssignDecoder de(vs, (unsigned char*)(&src), (unsigned char*)(&dst));
|
||||
dst.__x_pack_decode(de, dst, NULL);
|
||||
}
|
||||
|
||||
struct Data {
|
||||
int a;
|
||||
int b;
|
||||
std::string c;
|
||||
XPACK(O(a,b,c));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
Data d1;
|
||||
Data d2;
|
||||
d1.a = 5;
|
||||
d1.b = 10;
|
||||
d1.c = "hello";
|
||||
d2.b = 9;
|
||||
SetFields<Data>(d1, d2, "a,c");
|
||||
cout<<d2.a<<','<<d2.b<<','<<d2.c<<endl;
|
||||
return 0;
|
||||
}
|
||||
89
util/xpack/example/mysql.cpp
Executable file
89
util/xpack/example/mysql.cpp
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#include <iostream>
|
||||
#include <mysql/mysql.h>
|
||||
#include <xpack/mysql.h>
|
||||
#include <xpack/json.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct VID {
|
||||
int64_t Vid;
|
||||
int64_t vlen;
|
||||
string sid;
|
||||
int64_t level;
|
||||
XPACK(A(Vid, "db:vid"), O(vlen, sid, level));
|
||||
};
|
||||
|
||||
typedef char cfgstr[64];
|
||||
struct config {
|
||||
cfgstr host;
|
||||
uint32_t port;
|
||||
cfgstr user;
|
||||
cfgstr password;
|
||||
cfgstr dbname;
|
||||
XPACK(M(host, port, user, password, dbname))
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
MYSQL *mysql = NULL;
|
||||
|
||||
if (mysql_library_init(argc, argv, NULL)) {
|
||||
cout<<"could not initialize MySQL client library"<<endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mysql = mysql_init(mysql);
|
||||
|
||||
if (!mysql) {
|
||||
cout<<"Init faild, out of memory?"<<endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
config cfg;
|
||||
xpack::json::decode_file("./config.json", cfg);
|
||||
|
||||
if (!mysql_real_connect(mysql, /* MYSQL structure to use */
|
||||
cfg.host, /* server hostname or IP address */
|
||||
cfg.user, /* mysql user */
|
||||
cfg.password, /* password */
|
||||
cfg.dbname, /* default database to use, NULL for none */
|
||||
cfg.port, /* port number, 0 for default */
|
||||
NULL, /* socket file or named pipe name */
|
||||
CLIENT_FOUND_ROWS /* connection flags */ )) {
|
||||
cout<<"Connect failed"<<endl;
|
||||
} else {
|
||||
if (mysql_query(mysql, argv[1])) {
|
||||
cout<<"Query failed: "<<mysql_error(mysql)<<endl;
|
||||
} else {
|
||||
MYSQL_RES *result = mysql_store_result(mysql);
|
||||
|
||||
if (!result) {
|
||||
cout<<"Couldn't get results set: "<<mysql_error(mysql)<<endl;
|
||||
} else {
|
||||
VID vid;
|
||||
xpack::mysql::decode(result, vid); // decode first row
|
||||
|
||||
vector<VID> vids;
|
||||
xpack::mysql::decode(result, vids);// decode all rows
|
||||
|
||||
vector<int64_t> ids;
|
||||
xpack::mysql::decode(result, "vid", ids); // decode vid column of all rows
|
||||
|
||||
int64_t id;
|
||||
xpack::mysql::decode(result, "vid", id); // decode vid column of first row
|
||||
|
||||
cout<<xpack::json::encode(vid)<<endl;
|
||||
cout<<xpack::json::encode(vids)<<endl;
|
||||
cout<<xpack::json::encode(ids)<<endl;
|
||||
cout<<id<<endl;
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mysql_close(mysql);
|
||||
|
||||
mysql_library_end();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
61
util/xpack/example/sharedptr.cpp
Executable file
61
util/xpack/example/sharedptr.cpp
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct User {
|
||||
int64_t id;
|
||||
string name;
|
||||
string mail;
|
||||
std::shared_ptr<string> bio;
|
||||
User(int64_t i=0, const string& n="", const string& m=""):id(i),name(n),mail(m){}
|
||||
XPACK(O(id, name, mail, bio));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
User u1(1, "Jack", "jack@xpack.com");
|
||||
User u2;
|
||||
User u3;
|
||||
|
||||
string json = xpack::json::encode(u1);
|
||||
string xml = xpack::xml::encode(u1, "root");
|
||||
cout<<"========================"<<endl;
|
||||
cout<<json<<endl;
|
||||
cout<<xml<<endl;
|
||||
|
||||
cout<<"========================"<<endl;
|
||||
xpack::json::decode(json, u2);
|
||||
cout<<xpack::json::encode(u2)<<endl;
|
||||
xpack::xml::decode(xml, u3);
|
||||
cout<<xpack::xml::encode(u3, "root")<<endl;
|
||||
|
||||
cout<<"========================"<<endl;
|
||||
u1.bio.reset(new std::string("farmer"));
|
||||
json = xpack::json::encode(u1);
|
||||
xml = xpack::xml::encode(u1, "root");
|
||||
cout<<json<<endl;
|
||||
cout<<xml<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
61
util/xpack/example/sqlite.cpp
Executable file
61
util/xpack/example/sqlite.cpp
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
#include <iostream>
|
||||
#include <xpack/sqlite.h>
|
||||
#include <xpack/json.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct VID {
|
||||
int64_t Vid;
|
||||
int64_t vlen;
|
||||
string sid;
|
||||
int64_t level;
|
||||
XPACK(A(Vid, "db:vid"), O(vlen, sid, level));
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc;
|
||||
char *errMsg = NULL;
|
||||
sqlite *pDB = sqlite_open("./test.db", 0, &errMsg);
|
||||
if (NULL == pDB) {
|
||||
cout<<"open sqlite db fail:"<<errMsg<<endl;
|
||||
sqlite_freemem(errMsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nCols = 0;
|
||||
int nRows = 0;
|
||||
char **azResult = NULL;
|
||||
|
||||
int ret = sqlite_get_table(pDB, argv[1], &azResult, &nRows, &nCols, &errMsg);
|
||||
if (ret != SQLITE_OK) {
|
||||
cout<<"query sqlite db fail:"<<ret<<endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cout<<nRows<<','<<nCols<<endl;
|
||||
for (int i=0; i<nCols; ++i) {
|
||||
cout<<azResult[i]<<' ';
|
||||
}
|
||||
cout<<endl;
|
||||
int idx = nCols;
|
||||
for (int i=0; i<nRows; ++i) {
|
||||
for (int j=0; j<nCols; ++j, ++idx) {
|
||||
if (NULL == azResult[idx]) {
|
||||
cout<<"NULL"<<' ';
|
||||
} else {
|
||||
cout<<azResult[idx]<<' ';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
if (NULL != azResult) {
|
||||
sqlite_free_table(azResult);
|
||||
}
|
||||
if (NULL != errMsg) {
|
||||
sqlite_freemem(errMsg);
|
||||
}
|
||||
sqlite_close(pDB);
|
||||
|
||||
return 0;
|
||||
}
|
||||
118
util/xpack/example/union1.cpp
Executable file
118
util/xpack/example/union1.cpp
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Base {
|
||||
int a;
|
||||
int b;
|
||||
XPACK(O(a, b));
|
||||
};
|
||||
|
||||
struct Data {
|
||||
int type;
|
||||
union {
|
||||
Base b;
|
||||
int i;
|
||||
char s[10];
|
||||
};
|
||||
string email;
|
||||
string birthday;
|
||||
// 'type' determines which member of the union to use, so we put type in 'C'
|
||||
// union does not need to be put into XPACK, we will handled it in 'type'
|
||||
XPACK(C(data_uinon, F(0), type), O(email, birthday));
|
||||
};
|
||||
|
||||
struct User {
|
||||
string name;
|
||||
Data data;
|
||||
XPACK(O(name, data));
|
||||
};
|
||||
|
||||
namespace xpack { // must define in namespace xpack
|
||||
|
||||
template<class OBJ>
|
||||
bool data_uinon_decode(OBJ &obj, Data &d, const char*key, int &type, const Extend *ext) {
|
||||
(void)ext;
|
||||
obj.decode(key, type, ext);
|
||||
switch (type) {
|
||||
case 1:
|
||||
obj.decode("b", d.b, NULL); // key("b") should same as encode
|
||||
break;
|
||||
case 2:
|
||||
obj.decode("i", d.i, NULL);
|
||||
break;
|
||||
case 3:
|
||||
obj.decode("s", d.s, NULL);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class OBJ>
|
||||
bool data_uinon_encode(OBJ &obj, const Data &d, const char*key, const int &type, const Extend *ext) {
|
||||
(void)ext;
|
||||
obj.encode(key, type, NULL);
|
||||
switch (type) {
|
||||
case 1:
|
||||
obj.encode("b", d.b, NULL);
|
||||
break;
|
||||
case 2:
|
||||
obj.encode("i", d.i, NULL);
|
||||
break;
|
||||
case 3:
|
||||
obj.encode("s", d.s, NULL);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
User u;
|
||||
u.name = "Pony";
|
||||
u.data.type = 1;
|
||||
u.data.b.a = 10;
|
||||
u.data.b.b = 12;
|
||||
u.data.email = "Pony@xpack.com";
|
||||
u.data.birthday = "20200202";
|
||||
|
||||
string s = xpack::json::encode(u);
|
||||
cout<<s<<endl;
|
||||
|
||||
u.data.type = 2;
|
||||
u.data.i = 22;
|
||||
s = xpack::json::encode(u);
|
||||
cout<<s<<endl;
|
||||
|
||||
u.data.type = 3;
|
||||
strcpy(u.data.s, "hello");
|
||||
s = xpack::json::encode(u);
|
||||
cout<<s<<endl;
|
||||
|
||||
User u1;
|
||||
xpack::json::decode(s, u1);
|
||||
cout<<u1.data.s<<endl;
|
||||
return 0;
|
||||
}
|
||||
37
util/xpack/example/xml-content.cpp
Executable file
37
util/xpack/example/xml-content.cpp
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
#include <iostream>
|
||||
#include <xpack/xml.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Base {
|
||||
int a;
|
||||
int b;
|
||||
string c;
|
||||
XPACK(X(F(ATTR), a, b), X(F(XML_CONTENT), c));
|
||||
};
|
||||
|
||||
struct Root {
|
||||
Base root;
|
||||
XPACK(O(root));
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
Root r;
|
||||
r.root.a = 1;
|
||||
r.root.b = 2;
|
||||
r.root.c = "hello";
|
||||
string s = xpack::xml::encode(r, "root", 0, 4, ' ');
|
||||
cout<<s<<endl;
|
||||
string s1 = xpack::xml::encode(r, "root");
|
||||
cout<<s1<<endl;
|
||||
|
||||
Root r1,r2;
|
||||
xpack::xml::decode(s, r1);
|
||||
xpack::xml::decode(s1, r2);
|
||||
|
||||
cout<<xpack::xml::encode(r1, "r1")<<endl;
|
||||
cout<<xpack::xml::encode(r2, "r2")<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
67
util/xpack/example/xml.cpp
Executable file
67
util/xpack/example/xml.cpp
Executable file
|
|
@ -0,0 +1,67 @@
|
|||
#include <iostream>
|
||||
#include <xpack/xml.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Base {
|
||||
int a;
|
||||
int b;
|
||||
XPACK(O(a, b));//, X(F(ATTR), b));
|
||||
};
|
||||
|
||||
struct Root {
|
||||
Base root;
|
||||
XPACK(O(root));
|
||||
};
|
||||
|
||||
struct Top {
|
||||
int k;
|
||||
string n;
|
||||
vector<vector<Base> > bs;
|
||||
vector<int> vi;
|
||||
float f;
|
||||
std::string name; // cdata
|
||||
XPACK(O(k, n, f), A(bs, "xml:base,sbs", vi, "xml:vi,vl@x", name, "xml:name,cdata"));
|
||||
};
|
||||
|
||||
int main() {
|
||||
Top t;
|
||||
t.k = 666;
|
||||
t.n = "你好";
|
||||
t.f = 1.23333;
|
||||
t.vi.resize(2);
|
||||
t.vi[0] = 1;
|
||||
t.vi[1] = 2;
|
||||
t.bs.resize(2);
|
||||
t.bs[0].resize(2);
|
||||
t.bs[1].resize(2);
|
||||
t.bs[0][0].a = 100;
|
||||
t.bs[0][0].b = 200;
|
||||
t.bs[0][1].a = 101;
|
||||
t.bs[0][1].b = 201;
|
||||
t.bs[1][0].a = 110;
|
||||
t.bs[1][0].b = 210;
|
||||
t.bs[1][1].a = 111;
|
||||
t.bs[1][1].b = 211;
|
||||
t.name = "好好学习,天天向上<good good study, day day up>";
|
||||
string s = xpack::xml::encode(t, "root", 0, 4, ' ');
|
||||
cout<<s<<endl;
|
||||
|
||||
xpack::XmlEncoder en;
|
||||
en.SetMaxDecimalPlaces(3);
|
||||
cout<<"=========="<<endl<<en.encode(t, "root")<<endl;
|
||||
|
||||
Top t1;
|
||||
xpack::xml::decode(s, t1);
|
||||
cout<<xpack::xml::encode(t1, "root", 0, 4, ' ')<<endl;
|
||||
|
||||
Base b1;
|
||||
bool ret = xpack::XmlDecoder().decode("<root><a>1</a><b>2</b></root>", b1);
|
||||
cout<<ret<<','<<b1.a<<','<<b1.b<<endl;
|
||||
|
||||
Root r1;
|
||||
ret = xpack::XmlDecoder().decode("<root><a>1</a><b>2</b></root>", r1, true);
|
||||
cout<<ret<<','<<r1.root.a<<','<<r1.root.b<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
59
util/xpack/example/xpack_out.cpp
Executable file
59
util/xpack/example/xpack_out.cpp
Executable file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// #include <sys/time.h> linux only
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
};
|
||||
#endif
|
||||
|
||||
// timeval is thirdparty struct
|
||||
XPACK_OUT(timeval, O(tv_sec, tv_usec));
|
||||
|
||||
struct T {
|
||||
int a;
|
||||
string b;
|
||||
timeval t;
|
||||
XPACK(O(a, b, t));
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
T t;
|
||||
T r;
|
||||
t.a = 123;
|
||||
t.b = "xpack";
|
||||
t.t.tv_sec = 888;
|
||||
t.t.tv_usec = 999;
|
||||
string s = xpack::json::encode(t);
|
||||
cout<<s<<endl;
|
||||
xpack::json::decode(s, r);
|
||||
cout<<r.a<<','<<r.b<<','<<r.t.tv_sec<<','<<r.t.tv_usec<<endl;
|
||||
return 0;
|
||||
}
|
||||
121
util/xpack/example/xtype.cpp
Executable file
121
util/xpack/example/xtype.cpp
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Date {
|
||||
long unix_time;
|
||||
};
|
||||
|
||||
namespace xpack { // must define in namespace xpack
|
||||
|
||||
template<>
|
||||
struct is_xpack_xtype<Date> {static bool const value = true;};
|
||||
|
||||
// implement decode
|
||||
template<class OBJ>
|
||||
bool xpack_xtype_decode(OBJ &obj, Date &val, const Extend *ext) {
|
||||
std::string str;
|
||||
obj.decode(str, ext);
|
||||
if (str.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
tm ttm;
|
||||
|
||||
if (0 != strptime(str.c_str(), "%Y-%m-%d %H:%M:%S", &ttm)) {
|
||||
val.unix_time = mktime(&ttm);
|
||||
} else {
|
||||
val.unix_time = 0;
|
||||
}
|
||||
#else
|
||||
static int days[]={31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 32};
|
||||
struct tm ttm={0};
|
||||
sscanf_s(str.c_str(), "%d-%d-%d %d:%d:%d", &ttm.tm_year, &ttm.tm_mon, &ttm.tm_mday, &ttm.tm_hour, &ttm.tm_min, &ttm.tm_sec);
|
||||
ttm.tm_mon-=1; // mon[0-11]
|
||||
ttm.tm_year-=1900; // since 1900
|
||||
val.unix_time = mktime(&ttm);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// implement encode
|
||||
template<class OBJ>
|
||||
bool xpack_xtype_encode(OBJ &obj, const char*key, const Date &val, const Extend *ext) {
|
||||
time_t tt = (time_t)val.unix_time;
|
||||
tm ttm;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
localtime_r(&tt, &ttm);
|
||||
#else
|
||||
localtime_s(&ttm, &tt);
|
||||
#endif
|
||||
|
||||
char buf[64];
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ttm);
|
||||
return obj.encode(key, buf, ext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct User {
|
||||
int64_t id;
|
||||
string name;
|
||||
string mail;
|
||||
Date d;
|
||||
User(int64_t i=0, const string& n="", const string& m="", long _d=0):id(i),name(n),mail(m){d.unix_time = _d;}
|
||||
XPACK(O(id, name, mail, d));
|
||||
};
|
||||
|
||||
struct Group {
|
||||
string name;
|
||||
int64_t master;
|
||||
vector<User> members;
|
||||
XPACK(O(name, master, members));
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
Group g;
|
||||
g.name = "C++";
|
||||
g.master = 2019;
|
||||
g.members.resize(2);
|
||||
g.members[0] = User(1, "Jack", "jack@xpack.com", 1);
|
||||
g.members[1] = User(2, "Pony", "pony@xpack.com", 1609249232);
|
||||
|
||||
string json = xpack::json::encode(g, 0, 2, ' ');
|
||||
cout<<json<<endl;
|
||||
|
||||
string xml = xpack::xml::encode(g, "root", 0, 2, ' ');
|
||||
cout<<xml<<endl;
|
||||
|
||||
Group n1;
|
||||
xpack::json::decode(json, n1);
|
||||
cout<<n1.name<<';'<<n1.members[0].name<<';'<<n1.members[0].d.unix_time<<endl;
|
||||
|
||||
Group n2;
|
||||
xpack::xml::decode(xml, n2);
|
||||
cout<<n2.name<<';'<<n2.members[1].name<<';'<<n2.members[1].d.unix_time<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
108
util/xpack/example/xtype_advance.cpp
Executable file
108
util/xpack/example/xtype_advance.cpp
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// The requirement is to encode seq1 when type==1, and encode seq2 when type==2
|
||||
struct Sub {
|
||||
int type;
|
||||
string seq1;
|
||||
string seq2;
|
||||
XPACK(O(type, seq1, seq2));
|
||||
};
|
||||
|
||||
|
||||
struct Test {
|
||||
unsigned int uid;
|
||||
string name;
|
||||
Sub sub;
|
||||
XPACK(O(uid, name, sub));
|
||||
};
|
||||
|
||||
namespace xpack {
|
||||
|
||||
template<>
|
||||
struct is_xpack_xtype<Sub> {static bool const value = true;};
|
||||
|
||||
template <class Decoder>
|
||||
bool xpack_xtype_decode(Decoder& de, Sub &data, const xpack::Extend *ext) {
|
||||
de.decode_struct(data, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BaseEncoder>
|
||||
class MyEncoder {
|
||||
public:
|
||||
MyEncoder(BaseEncoder&b, const Sub&sub):_b(&b), _s(&sub){}
|
||||
template <class T>
|
||||
bool encode(const char*key, const T&val, const xpack::Extend *ext) {
|
||||
if (strcmp(key, "seq1") == 0) {
|
||||
if (_s->type == 1) {
|
||||
return _b->encode(key, val, ext);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (strcmp(key, "seq2") == 0) {
|
||||
if (_s->type == 2) {
|
||||
return _b->encode(key, val, ext);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return _b->encode(key, val, ext);
|
||||
}
|
||||
}
|
||||
private:
|
||||
BaseEncoder *_b;
|
||||
const Sub *_s;
|
||||
};
|
||||
|
||||
template <class Encoder>
|
||||
bool xpack_xtype_encode(Encoder &en, const char *name, const Sub &data, const xpack::Extend *ext) {
|
||||
(void)name;
|
||||
MyEncoder<Encoder> my(en, data);
|
||||
data.__x_pack_encode(my, data, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
Test t;
|
||||
t.uid = 127;
|
||||
t.name = "PonyJack";
|
||||
t.sub.type = 1;
|
||||
t.sub.seq1 = "10086";
|
||||
t.sub.seq2 = "10001";
|
||||
|
||||
string str = xpack::json::encode(t);
|
||||
cout<<str<<endl;
|
||||
|
||||
Test n;
|
||||
xpack::json::decode(str, t);
|
||||
cout<<t.uid<<endl;
|
||||
|
||||
t.sub.type = 2;
|
||||
cout<<xpack::json::encode(t)<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
65
util/xpack/example/yaml.cpp
Executable file
65
util/xpack/example/yaml.cpp
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "xpack/yaml.h"
|
||||
#include "xpack/json.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct User {
|
||||
int64_t id;
|
||||
string name;
|
||||
string mail;
|
||||
User(int64_t i=0, const string& n="", const string& m=""):id(i),name(n),mail(m){}
|
||||
XPACK(O(id, name, mail));
|
||||
};
|
||||
|
||||
struct Group {
|
||||
string name;
|
||||
int64_t master;
|
||||
map<string, string> flags;
|
||||
vector<User> members;
|
||||
User arrays[2];
|
||||
XPACK(O(name, master, flags, members, arrays));
|
||||
};
|
||||
|
||||
int main() {
|
||||
User u;
|
||||
xpack::yaml::decode_file("./test.yml", u);
|
||||
string json = xpack::json::encode(u);
|
||||
cout<<"json:"<<json<<endl;
|
||||
cout<<"yaml is =================="<<endl<<xpack::yaml::encode(u)<<endl<<"=================="<<endl;
|
||||
|
||||
Group g;
|
||||
g.name = "C++";
|
||||
g.master = 2019;
|
||||
g.members.resize(2);
|
||||
g.members[0] = User(1, "Jack", "jack@xpack.com");
|
||||
g.members[1] = User(2, "Pony", "pony@xpack.com");
|
||||
g.arrays[0] = g.members[0];
|
||||
g.arrays[1] = g.members[1];
|
||||
g.flags["a"] = "good";
|
||||
g.flags["b"] = "nice";
|
||||
string ys = xpack::yaml::encode(g);
|
||||
cout<<"yaml is =================="<<endl<<ys<<endl<<"=================="<<endl;
|
||||
|
||||
Group g1;
|
||||
xpack::yaml::decode(ys, g1);
|
||||
cout<<xpack::json::encode(g1)<<endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
188
util/xpack/extend.h
Executable file
188
util/xpack/extend.h
Executable file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_EXTEND_H
|
||||
#define __X_PACK_EXTEND_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
// user flag
|
||||
#define X_PACK_FLAG_0 0
|
||||
#define X_PACK_FLAG_OE (1<<0) // omitempty, in encode
|
||||
#define X_PACK_FLAG_M (1<<1) // mandatory, in decode
|
||||
#define X_PACK_FLAG_EN (1<<2) // empty as null, in json encode
|
||||
#define X_PACK_FLAG_SL (1<<3) // encode as one line, currently only supports json vector
|
||||
|
||||
#define X_PACK_FLAG_ATTR (1<<15) // for xml encode, encode in attribute
|
||||
|
||||
// for xml encode/decode: <label attr1="a" attr2="b">content</label>
|
||||
// CONTENT flag for decode and encode content
|
||||
// A structure can only have one CONTENT flag. If multiple ones are defined, the behavior is undefined.
|
||||
#define X_PACK_FLAG_XML_CONTENT (1<<16)
|
||||
|
||||
// control flag
|
||||
#define X_PACK_CTRL_FLAG_INHERIT (1<<0)
|
||||
|
||||
// Alias name. [def ][type:name[,flag,key@value,flag]] def not support flag
|
||||
struct Alias {
|
||||
const char *raw; // raw name
|
||||
const char *alias; // alias define
|
||||
|
||||
struct Type {
|
||||
std::string name;
|
||||
std::set<std::string> flags;
|
||||
std::map<std::string, std::string> kv_flags;
|
||||
};
|
||||
|
||||
Alias(const char *_raw, const char *_alias):raw(_raw), alias(_alias) {
|
||||
std::vector<std::string> tps;
|
||||
Util::split(tps, alias, ' ');
|
||||
|
||||
for (size_t i=0; i<tps.size(); ++i) {
|
||||
std::vector<std::string> typeFlag;
|
||||
Util::split(typeFlag, tps[i], ':', 1);
|
||||
|
||||
if (typeFlag.size() == 1) { // no ':', default name
|
||||
def = tps[i];
|
||||
} else { // type:name[,flags]
|
||||
Type tp;
|
||||
|
||||
std::vector<std::string> nameFlags;
|
||||
Util::split(nameFlags, typeFlag[1], ',');
|
||||
tp.name = nameFlags[0];
|
||||
if (nameFlags.size() > 1) {
|
||||
for (size_t j=1; j<nameFlags.size(); ++j) {
|
||||
std::vector<std::string> kvFlag;
|
||||
Util::split(kvFlag, nameFlags[j], '@', 1);
|
||||
if (kvFlag.size() == 1) {
|
||||
tp.flags.insert(nameFlags[j]);
|
||||
} else {
|
||||
tp.kv_flags[kvFlag[0]] = kvFlag[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
types[typeFlag[0]] = tp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *Name(const char *type) const {
|
||||
std::map<std::string, Type>::const_iterator iter = types.find(type);
|
||||
if (iter == types.end()) {
|
||||
if (def.empty()) {
|
||||
return raw;
|
||||
} else {
|
||||
return def.c_str();
|
||||
}
|
||||
} else {
|
||||
return iter->second.name.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
bool Flag(const std::string&type, const std::string& flag, std::string *value=NULL) const {
|
||||
std::map<std::string, Type>::const_iterator it1 = types.find(type);
|
||||
if (it1 != types.end()) {
|
||||
if (it1->second.flags.find(flag) != it1->second.flags.end()) {
|
||||
return true;
|
||||
}
|
||||
std::map<std::string, std::string>::const_iterator it2 = it1->second.kv_flags.find(flag);
|
||||
if (it2 != it1->second.kv_flags.end()) {
|
||||
if (NULL != value) {
|
||||
*value = it2->second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
std::string def; // default name
|
||||
std::map<std::string, Type> types;
|
||||
};
|
||||
|
||||
struct Extend {
|
||||
int flag;
|
||||
int ctrl_flag;
|
||||
const Alias *alias;
|
||||
|
||||
Extend(int _flag, const Alias *_alias):flag(_flag), ctrl_flag(0), alias(_alias) {
|
||||
}
|
||||
|
||||
Extend(const Extend *ext) {
|
||||
if (NULL != ext) {
|
||||
flag = ext->flag;
|
||||
ctrl_flag = ext->ctrl_flag;
|
||||
alias = ext->alias;
|
||||
} else {
|
||||
flag = 0;
|
||||
ctrl_flag = 0;
|
||||
alias = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int Flag(const Extend *ext) {
|
||||
if (NULL == ext) {
|
||||
return 0;
|
||||
} else {
|
||||
return ext->flag;
|
||||
}
|
||||
}
|
||||
|
||||
static int CtrlFlag(const Extend *ext) {
|
||||
if (NULL == ext) {
|
||||
return 0;
|
||||
} else {
|
||||
return ext->ctrl_flag;
|
||||
}
|
||||
}
|
||||
|
||||
static bool AliasFlag(const Extend *ext, const std::string&type, const std::string& flag, std::string *value=NULL) {
|
||||
if (NULL==ext || NULL==ext->alias) {
|
||||
return false;
|
||||
}
|
||||
return ext->alias->Flag(type, flag, value);
|
||||
}
|
||||
|
||||
static bool OmitEmpty(const Extend *ext) {
|
||||
return NULL!=ext && (ext->flag&X_PACK_FLAG_OE);
|
||||
}
|
||||
static bool EmptyNull(const Extend *ext) {
|
||||
return NULL!=ext && (ext->flag&X_PACK_FLAG_EN);
|
||||
}
|
||||
static bool Mandatory(const Extend *ext) {
|
||||
return NULL!=ext && (ext->flag&X_PACK_FLAG_M);
|
||||
}
|
||||
static bool Attribute(const Extend *ext) {
|
||||
return NULL!=ext && (ext->flag&X_PACK_FLAG_ATTR);
|
||||
}
|
||||
static bool XmlContent(const Extend *ext) {
|
||||
return NULL!=ext && (ext->flag&X_PACK_FLAG_XML_CONTENT);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
557
util/xpack/gtest/bson_test.cpp
Executable file
557
util/xpack/gtest/bson_test.cpp
Executable file
|
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Linux only, need gtest
|
||||
|
||||
#include <iostream>
|
||||
#ifdef XGTEST
|
||||
#include<gtest/gtest.h>
|
||||
#else
|
||||
#include "gtest_stub.h"
|
||||
#endif
|
||||
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/bson.h"
|
||||
#include "string.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Base {
|
||||
int a;
|
||||
string b;
|
||||
Base(const int _a=0, const string&_b=""):a(_a), b(_b){}
|
||||
XPACK(O(a, b));
|
||||
};
|
||||
|
||||
struct POD {
|
||||
int a;
|
||||
char b[10];
|
||||
XPACK(O(a, b));
|
||||
};
|
||||
|
||||
// ++++++++++++++++++++++BuiltInTypes++++++++++++++++++++++++++++
|
||||
struct BuiltInTypes {
|
||||
signed char sch;
|
||||
char ch;
|
||||
unsigned char uch;
|
||||
short sh;
|
||||
unsigned short ush;
|
||||
int i;
|
||||
unsigned int ui;
|
||||
long l;
|
||||
unsigned long ul;
|
||||
long long ll;
|
||||
unsigned long long ull;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
bool b;
|
||||
XPACK(AF(F(ATTR), sch, "xml:s:ch"), X(F(ATTR), ch, uch, sh, ush), O(i, ui, l, ul, ll, ull, f, d, ld, b));
|
||||
};
|
||||
|
||||
|
||||
void checkBuiltInTypes(const BuiltInTypes&a, const BuiltInTypes&b) {
|
||||
EXPECT_EQ(a.sch, b.sch);
|
||||
EXPECT_EQ(a.ch, b.ch);
|
||||
EXPECT_EQ(a.uch, b.uch);
|
||||
EXPECT_EQ(a.sh, b.sh);
|
||||
EXPECT_EQ(a.ush, b.ush);
|
||||
EXPECT_EQ(a.i, b.i);
|
||||
EXPECT_EQ(a.ui, b.ui);
|
||||
EXPECT_EQ(a.l, b.l);
|
||||
EXPECT_EQ(a.ul, b.ul);
|
||||
EXPECT_EQ(a.ll, b.ll);
|
||||
EXPECT_EQ(a.ull, b.ull);
|
||||
EXPECT_FLOAT_EQ(a.f, b.f);
|
||||
EXPECT_DOUBLE_EQ(a.d, b.d);
|
||||
EXPECT_DOUBLE_EQ(a.ld, b.ld);
|
||||
EXPECT_TRUE(a.b);
|
||||
}
|
||||
TEST(builtin, types) {
|
||||
BuiltInTypes bt;
|
||||
bt.sch = 0x7f;
|
||||
bt.ch = 0x7f;
|
||||
bt.uch = 0x80;
|
||||
bt.sh = 0x7fff;
|
||||
bt.ush = 0x8000;
|
||||
bt.i = 0x7fffffff;
|
||||
bt.ui = 0x80000000;
|
||||
bt.l = 0x7fffffffffffffff;
|
||||
bt.ul = 0x8000000000000000;
|
||||
bt.ll = bt.l;
|
||||
bt.ull = bt.ul;
|
||||
bt.f = 1.234;
|
||||
bt.d = 9.678;
|
||||
bt.ld = 30.678;
|
||||
bt.b = true;
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(bt);
|
||||
cout<<"bson:"<<js<<endl;
|
||||
|
||||
BuiltInTypes j1;
|
||||
xpack::bson::decode(en.encode(bt), j1);
|
||||
checkBuiltInTypes(j1, bt);
|
||||
}
|
||||
|
||||
// ++++++++++++++++++++bit field+++++++++++++++++++++++++++
|
||||
struct BitField {
|
||||
short a:8;
|
||||
short b:8;
|
||||
|
||||
XPACK(B(F(0), a, b));
|
||||
};
|
||||
|
||||
void checkBitField(const BitField&a, const BitField&b) {
|
||||
EXPECT_EQ(a.a, b.a);
|
||||
EXPECT_EQ(a.b, b.b);
|
||||
}
|
||||
TEST(bitfiled, base) {
|
||||
BitField bf;
|
||||
bf.a = 0x70;
|
||||
bf.b = 0x7f;
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(bf);
|
||||
|
||||
BitField j1;
|
||||
xpack::bson::decode(en.encode(bf), j1);
|
||||
checkBitField(j1, bf);
|
||||
}
|
||||
|
||||
// +++++++++++++++++++ enum +++++++++++++++++++++
|
||||
enum Enum1 {
|
||||
E0 = 0,
|
||||
E1 = 1,
|
||||
};
|
||||
enum class Enum2:int64_t {
|
||||
E2 = 2,
|
||||
E3 = 3,
|
||||
};
|
||||
struct EnumBase {
|
||||
Enum1 e1;
|
||||
Enum2 e2;
|
||||
|
||||
XPACK(O(e1), E(F(0), e2));
|
||||
};
|
||||
|
||||
void checkEnumBase(const EnumBase&a, const EnumBase&b) {
|
||||
EXPECT_EQ(a.e1, b.e1);
|
||||
EXPECT_EQ(a.e2, b.e2);
|
||||
}
|
||||
TEST(enum, base) {
|
||||
EnumBase eb;
|
||||
eb.e1 = E0;
|
||||
eb.e2 = Enum2::E3;
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(eb);
|
||||
|
||||
EnumBase j1;
|
||||
xpack::bson::decode(en.encode(eb), j1);
|
||||
checkEnumBase(j1, eb);
|
||||
}
|
||||
|
||||
// ++++++++++++++++inherit+++++++++++++++++++++++++++++
|
||||
struct InheritBase {
|
||||
int b1;
|
||||
string b2;
|
||||
|
||||
XPACK(O(b1, b2));
|
||||
};
|
||||
|
||||
struct InheritChild:public InheritBase {
|
||||
int c1;
|
||||
string c2;
|
||||
|
||||
XPACK(I(InheritBase), O(c1, c2));
|
||||
};
|
||||
|
||||
void checkInherit(const InheritChild&a, const InheritChild&b) {
|
||||
EXPECT_EQ(a.b1, b.b1);
|
||||
EXPECT_EQ(a.b2, b.b2);
|
||||
EXPECT_EQ(a.c1, b.c1);
|
||||
EXPECT_EQ(a.c2, b.c2);
|
||||
}
|
||||
TEST(inherit, base) {
|
||||
InheritChild c;
|
||||
c.b1 = 1;
|
||||
c.b2 = "base";
|
||||
c.c1 = 2;
|
||||
c.c2 = "child";
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(c);
|
||||
|
||||
InheritChild j1;
|
||||
xpack::bson::decode(en.encode(c), j1);
|
||||
checkInherit(j1, c);
|
||||
}
|
||||
|
||||
// ++++++++++++++++++++++++array++++++++++++++++++++++++++
|
||||
struct Array {
|
||||
int a[3];
|
||||
char b[3];
|
||||
Base c[3];
|
||||
|
||||
XPACK(O(a, b, c));
|
||||
};
|
||||
|
||||
void checkArray(const Array&a, const Array&b) {
|
||||
EXPECT_EQ(a.a[0], b.a[0]);
|
||||
EXPECT_EQ(a.a[1], b.a[1]);
|
||||
EXPECT_EQ(a.a[2], b.a[2]);
|
||||
EXPECT_EQ(a.b[0], b.b[0]);
|
||||
EXPECT_EQ(a.b[1], b.b[1]);
|
||||
EXPECT_EQ(a.b[2], b.b[2]);
|
||||
EXPECT_EQ(a.c[0].a, b.c[0].a);
|
||||
EXPECT_EQ(a.c[0].b, b.c[0].b);
|
||||
EXPECT_EQ(a.c[1].a, b.c[1].a);
|
||||
EXPECT_EQ(a.c[1].b, b.c[1].b);
|
||||
EXPECT_EQ(a.c[2].a, b.c[2].a);
|
||||
EXPECT_EQ(a.c[2].b, b.c[2].b);
|
||||
}
|
||||
TEST(array, base) {
|
||||
Array a;
|
||||
a.a[0] = 1;
|
||||
a.a[1] = 2;
|
||||
a.a[2] = 3;
|
||||
a.b[0] = 'g';
|
||||
a.b[1] = 'o';
|
||||
a.b[2] = '\0';
|
||||
a.c[0].a = 11;
|
||||
a.c[1].a = 12;
|
||||
a.c[2].a = 13;
|
||||
a.c[0].b = "hello";
|
||||
a.c[1].b = "good";
|
||||
a.c[1].b = "nice";
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(a);
|
||||
|
||||
Array j1;
|
||||
xpack::bson::decode(en.encode(a), j1);
|
||||
checkArray(j1, a);
|
||||
}
|
||||
|
||||
|
||||
// +++++++++++++++ container ++++++++++++++++++++++
|
||||
struct ContainerBase {
|
||||
map<string, int> m;
|
||||
set<int> s;
|
||||
vector<int> v;
|
||||
list<int> l;
|
||||
|
||||
vector<vector<int> > vv;
|
||||
|
||||
XPACK(O(m, s, v, l, vv));
|
||||
};
|
||||
|
||||
void checkContainerBase(ContainerBase&cb) {
|
||||
EXPECT_EQ(cb.m.size(), 2U);
|
||||
EXPECT_EQ(cb.m["a"], 1);
|
||||
EXPECT_EQ(cb.m["b"], 2);
|
||||
EXPECT_EQ(cb.s.size(), 2U);
|
||||
EXPECT_TRUE(cb.s.find(3)!=cb.s.end());
|
||||
EXPECT_TRUE(cb.s.find(4)!=cb.s.end());
|
||||
EXPECT_TRUE(cb.s.find(5)==cb.s.end());
|
||||
EXPECT_EQ(cb.v.size(), 2U);
|
||||
EXPECT_EQ(cb.v[0], 5);
|
||||
EXPECT_EQ(cb.v[1], 6);
|
||||
EXPECT_EQ(cb.l.size(), 2U);
|
||||
EXPECT_EQ(*(cb.l.begin()), 7);
|
||||
EXPECT_EQ(*(++cb.l.begin()), 8);
|
||||
|
||||
EXPECT_EQ(cb.vv.size(), 2U);
|
||||
EXPECT_EQ(cb.vv[0].size(), 2U);
|
||||
EXPECT_EQ(cb.vv[1].size(), 2U);
|
||||
EXPECT_EQ(cb.vv[0][0], 11);
|
||||
EXPECT_EQ(cb.vv[0][1], 12);
|
||||
EXPECT_EQ(cb.vv[1][0], 22);
|
||||
EXPECT_EQ(cb.vv[1][1], 23);
|
||||
}
|
||||
TEST(container, base) {
|
||||
string s = "{\"m\":{\"a\":1, \"b\":2}, \"s\":[3, 4], \"v\":[5,6], \"l\":[7, 8], \"vv\":[[11,12],[22,23]]}";
|
||||
|
||||
ContainerBase cb;
|
||||
xpack::json::decode(s, cb);
|
||||
checkContainerBase(cb);
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(cb);
|
||||
|
||||
ContainerBase j1;
|
||||
xpack::bson::decode(en.encode(cb), j1);
|
||||
checkContainerBase(j1);
|
||||
}
|
||||
struct ContainerStruct {
|
||||
map<string, Base> m;
|
||||
vector<Base> v;
|
||||
list<Base> l;
|
||||
|
||||
vector<vector<Base> > vv;
|
||||
|
||||
XPACK(O(m, v, l, vv));
|
||||
};
|
||||
|
||||
void checkContainerStruct(ContainerStruct&a) {
|
||||
EXPECT_EQ(a.m.size(), 2U);
|
||||
EXPECT_EQ(a.m["a"].a, 1);
|
||||
EXPECT_EQ(a.m["a"].b, "good");
|
||||
EXPECT_EQ(a.m["b"].a, 2);
|
||||
EXPECT_EQ(a.m["b"].b, "nice");
|
||||
|
||||
EXPECT_EQ(a.v.size(), 2U);
|
||||
EXPECT_EQ(a.v[0].a, 3);
|
||||
EXPECT_EQ(a.v[0].b, "hello");
|
||||
EXPECT_EQ(a.v[1].a, 4);
|
||||
EXPECT_EQ(a.v[1].b, "wow");
|
||||
|
||||
list<Base>::const_iterator lit = a.l.begin();
|
||||
EXPECT_EQ(a.l.size(), 2U);
|
||||
EXPECT_EQ(lit->a, 5);
|
||||
EXPECT_EQ(lit->b, "dida");
|
||||
++lit;
|
||||
EXPECT_EQ(lit->a, 6);
|
||||
EXPECT_EQ(lit->b, "haha");
|
||||
|
||||
EXPECT_EQ(a.vv.size(), 2U);
|
||||
EXPECT_EQ(a.vv[0].size(), 1U);
|
||||
EXPECT_EQ(a.vv[1].size(), 2U);
|
||||
EXPECT_EQ(a.vv[0][0].a, 7);
|
||||
EXPECT_EQ(a.vv[0][0].b, "lala");
|
||||
EXPECT_EQ(a.vv[1][0].a, 8);
|
||||
EXPECT_EQ(a.vv[1][0].b, "wawa");
|
||||
EXPECT_EQ(a.vv[1][1].a, 9);
|
||||
EXPECT_EQ(a.vv[1][1].b, "kaka");
|
||||
}
|
||||
TEST(container, struct) {
|
||||
ContainerStruct cb;
|
||||
cb.m["a"] = Base(1, "good");
|
||||
cb.m["b"] = Base(2, "nice");
|
||||
cb.v.push_back(Base(3, "hello"));
|
||||
cb.v.push_back(Base(4, "wow"));
|
||||
cb.l.push_back(Base(5, "dida"));
|
||||
cb.l.push_back(Base(6, "haha"));
|
||||
cb.vv.resize(2);
|
||||
cb.vv[0].resize(1);
|
||||
cb.vv[1].resize(2);
|
||||
cb.vv[0][0].a = 7;
|
||||
cb.vv[0][0].b = "lala";
|
||||
cb.vv[1][0].a = 8;
|
||||
cb.vv[1][0].b = "wawa";
|
||||
cb.vv[1][1].a = 9;
|
||||
cb.vv[1][1].b = "kaka";
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js = en.encode_as_json(cb);
|
||||
|
||||
ContainerStruct j1;
|
||||
xpack::bson::decode(en.encode(cb), j1);
|
||||
checkContainerStruct(j1);
|
||||
}
|
||||
|
||||
// ++++++++++++++++++ BSON TYPES ++++++++++++++++++++++++++++
|
||||
struct BsonTypes {
|
||||
bson_date_time_t dt;
|
||||
bson_timestamp_t ts;
|
||||
bson_binary_t binary;
|
||||
bson_regex_t regex;
|
||||
|
||||
bson_oid_t oid;
|
||||
bson_decimal128_t decimal;
|
||||
XPACK(A(oid, "_id"), O(dt, ts, binary, regex, decimal));
|
||||
};
|
||||
|
||||
void checkBsonTypes(const BsonTypes&a, const BsonTypes&b, bool checkDecimal) {
|
||||
EXPECT_EQ(a.dt.ts, b.dt.ts);
|
||||
|
||||
EXPECT_EQ(a.ts.timestamp, b.ts.timestamp);
|
||||
EXPECT_EQ(a.ts.increment, b.ts.increment);
|
||||
|
||||
EXPECT_EQ(a.binary.data, b.binary.data);
|
||||
EXPECT_EQ(a.binary.subType, b.binary.subType);
|
||||
|
||||
EXPECT_EQ(a.regex.pattern, b.regex.pattern);
|
||||
EXPECT_EQ(a.regex.options, b.regex.options);
|
||||
|
||||
EXPECT_EQ(0, memcmp(a.oid.bytes, b.oid.bytes, sizeof(a.oid.bytes)));
|
||||
|
||||
if (checkDecimal) {
|
||||
EXPECT_EQ(a.decimal.high, b.decimal.high);
|
||||
EXPECT_EQ(a.decimal.low, b.decimal.low);
|
||||
}
|
||||
}
|
||||
TEST(base, bson_types) {
|
||||
BsonTypes bt;
|
||||
|
||||
bt.dt.ts = 1638374400018;
|
||||
|
||||
bt.ts.timestamp = 1638374400;
|
||||
bt.ts.increment = 1;
|
||||
|
||||
bt.binary.data = "hello";
|
||||
bt.binary.subType = BSON_SUBTYPE_USER;
|
||||
|
||||
bt.regex.pattern = "^([0-9a-zA-Z]+)";
|
||||
bt.regex.options = "i";
|
||||
bt.regex.ver = 2;
|
||||
|
||||
uint8_t bytes[] = {0x57, 0xe1, 0x93, 0xd7, 0xa9, 0xcc, 0x81, 0xb4, 0x02, 0x74, 0x98, 0xb5};
|
||||
memcpy((void*)bt.oid.bytes, bytes, sizeof(bt.oid.bytes));
|
||||
|
||||
bt.decimal.high = 1;
|
||||
bt.decimal.low = 2;
|
||||
|
||||
string js = xpack::json::encode(bt);
|
||||
cout<<"json:"<<js<<endl;
|
||||
BsonTypes bt1;
|
||||
xpack::json::decode(js, bt1);
|
||||
checkBsonTypes(bt, bt1, false);
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
string js1 = en.encode_as_json(bt);
|
||||
cout<<"bjson:"<<js1<<endl;
|
||||
BsonTypes bt2;
|
||||
xpack::json::decode(js1, bt2);
|
||||
checkBsonTypes(bt, bt2, false);
|
||||
|
||||
BsonTypes bt3;
|
||||
xpack::bson::decode(en.encode(bt), bt3);
|
||||
checkBsonTypes(bt, bt3, true);
|
||||
}
|
||||
|
||||
TEST(bson, builders) {
|
||||
static xpack::BsonBuilder bd("{?:?, 'users':?}");
|
||||
EXPECT_TRUE(bd.Error().empty());
|
||||
|
||||
vector<int> v(3);
|
||||
v[0] = 1; v[1] = 2; v[2] = 3;
|
||||
cout<<"json1:"<<bd.EncodeAsJson("hi", true, v)<<endl;
|
||||
cout<<"json2:"<<bd.EncodeAsJson("uid", 123.0, "LiLei/HanMeimei/Jim")<<endl;
|
||||
cout<<"json3:"<<bd.EncodeAsJson("Lang", "C++", "")<<endl;
|
||||
}
|
||||
|
||||
// +++++++++++++++++++ QT ++++++++++++++++++++
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
struct ContainerQT {
|
||||
QMap<string, Base> m;
|
||||
QVector<Base> v;
|
||||
QList<Base> l;
|
||||
|
||||
QVector<QVector<Base> > vv;
|
||||
|
||||
XPACK(O(m, v, l, vv));
|
||||
};
|
||||
|
||||
void checkContainerQT(ContainerQT&a) {
|
||||
EXPECT_EQ(a.m.size(), 2);
|
||||
EXPECT_EQ(a.m["a"].a, 1);
|
||||
EXPECT_EQ(a.m["a"].b, "good");
|
||||
EXPECT_EQ(a.m["b"].a, 2);
|
||||
EXPECT_EQ(a.m["b"].b, "nice");
|
||||
|
||||
EXPECT_EQ(a.v.size(), 2);
|
||||
EXPECT_EQ(a.v[0].a, 3);
|
||||
EXPECT_EQ(a.v[0].b, "hello");
|
||||
EXPECT_EQ(a.v[1].a, 4);
|
||||
EXPECT_EQ(a.v[1].b, "wow");
|
||||
|
||||
QList<Base>::const_iterator lit = a.l.begin();
|
||||
EXPECT_EQ(a.l.size(), 2);
|
||||
EXPECT_EQ(lit->a, 5);
|
||||
EXPECT_EQ(lit->b, "dida");
|
||||
++lit;
|
||||
EXPECT_EQ(lit->a, 6);
|
||||
EXPECT_EQ(lit->b, "haha");
|
||||
|
||||
EXPECT_EQ(a.vv.size(), 2);
|
||||
EXPECT_EQ(a.vv[0].size(), 1);
|
||||
EXPECT_EQ(a.vv[1].size(), 2);
|
||||
EXPECT_EQ(a.vv[0][0].a, 7);
|
||||
EXPECT_EQ(a.vv[0][0].b, "lala");
|
||||
EXPECT_EQ(a.vv[1][0].a, 8);
|
||||
EXPECT_EQ(a.vv[1][0].b, "wawa");
|
||||
EXPECT_EQ(a.vv[1][1].a, 9);
|
||||
EXPECT_EQ(a.vv[1][1].b, "kaka");
|
||||
}
|
||||
TEST(container, QT) {
|
||||
ContainerQT cb;
|
||||
cb.m["a"] = Base(1, "good");
|
||||
cb.m["b"] = Base(2, "nice");
|
||||
cb.v.push_back(Base(3, "hello"));
|
||||
cb.v.push_back(Base(4, "wow"));
|
||||
cb.l.push_back(Base(5, "dida"));
|
||||
cb.l.push_back(Base(6, "haha"));
|
||||
cb.vv.resize(2);
|
||||
cb.vv[0].resize(1);
|
||||
cb.vv[1].resize(2);
|
||||
cb.vv[0][0].a = 7;
|
||||
cb.vv[0][0].b = "lala";
|
||||
cb.vv[1][0].a = 8;
|
||||
cb.vv[1][0].b = "wawa";
|
||||
cb.vv[1][1].a = 9;
|
||||
cb.vv[1][1].b = "kaka";
|
||||
|
||||
xpack::BsonEncoder en;
|
||||
en.encode(NULL, cb, NULL);
|
||||
string js = en.Json();
|
||||
|
||||
ContainerQT j1;
|
||||
xpack::bson::decode(en.String(), j1);
|
||||
checkContainerQT(j1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// +++++++++++++++++ flags ++++++++++++++++++
|
||||
struct FlagM {
|
||||
int a;
|
||||
string b;
|
||||
XPACK(O(a), M(b));
|
||||
};
|
||||
TEST(flags, M) {
|
||||
static xpack::BsonBuilder bd("{'a':1}");
|
||||
|
||||
bool except = false;
|
||||
try {
|
||||
FlagM j1;
|
||||
xpack::bson::decode(bd.Encode(), j1);
|
||||
} catch(...) {
|
||||
except = true;
|
||||
}
|
||||
EXPECT_TRUE(except);
|
||||
}
|
||||
// ++++++++++++++++++bug history+++++++++++++++++++++++
|
||||
TEST(bughis, notexists) {
|
||||
Base b(9, "");
|
||||
|
||||
static xpack::BsonBuilder bd("{'a':1}");
|
||||
xpack::bson::decode(bd.Encode(), b);
|
||||
EXPECT_EQ(b.a, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#ifdef XGTEST
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
TC_CONTAINER::RUN();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
167
util/xpack/gtest/gtest_stub.h
Executable file
167
util/xpack/gtest/gtest_stub.h
Executable file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __X_GTEST_STUB_H
|
||||
#define __X_GTEST_STUB_H
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include <xpack/traits.h>
|
||||
#include <xpack/numeric.h>
|
||||
|
||||
// test callback function
|
||||
typedef void(*test_case)();
|
||||
|
||||
// a test case
|
||||
struct text_ctx {
|
||||
const char *group;
|
||||
const char *name;
|
||||
test_case tc;
|
||||
};
|
||||
|
||||
class Status {
|
||||
public:
|
||||
static int&c() {
|
||||
static int _c;
|
||||
return _c;
|
||||
}
|
||||
};
|
||||
|
||||
// to collect all test
|
||||
class TC_CONTAINER {
|
||||
public:
|
||||
// add a test case to container
|
||||
static void add(test_case tc, const char* g, const char*n) {
|
||||
text_ctx tx;
|
||||
tx.group = g;
|
||||
tx.name = n;
|
||||
tx.tc = tc;
|
||||
I()._tcs.push_back(tx);
|
||||
}
|
||||
|
||||
// run all test case
|
||||
static void RUN() {
|
||||
const std::vector<text_ctx>& tcs = I()._tcs;
|
||||
for (size_t i=0; i<tcs.size(); ++i) {
|
||||
Status::c() = 0;
|
||||
std::cout<<tcs[i].group<<" "<<tcs[i].name<<" start --->"<<std::endl;
|
||||
tcs[i].tc();
|
||||
if (Status::c() == 0) {
|
||||
std::cout<<tcs[i].group<<" "<<tcs[i].name<<" passed.";
|
||||
} else {
|
||||
std::cout<<tcs[i].group<<" "<<tcs[i].name<<" fail. ";
|
||||
}
|
||||
std::cout<<"<---"<<std::endl;
|
||||
}
|
||||
}
|
||||
private:
|
||||
// singleton
|
||||
static TC_CONTAINER& I() {
|
||||
static TC_CONTAINER _inst;
|
||||
return _inst;
|
||||
}
|
||||
|
||||
std::vector<text_ctx> _tcs;
|
||||
};
|
||||
|
||||
// add test case in ctor
|
||||
class AUTO_ADD_TC {
|
||||
public:
|
||||
AUTO_ADD_TC(test_case tc, const char* g, const char*n) {
|
||||
TC_CONTAINER::add(tc, g, n);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// type convert to support std::cout
|
||||
class TV {
|
||||
public:
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
template <class TYPE>
|
||||
static typename std::enable_if<std::is_enum<TYPE>::value, int64_t>::type tv(const TYPE &d) {
|
||||
return (int64_t)d;
|
||||
}
|
||||
template <class TYPE>
|
||||
static typename std::enable_if<!std::is_enum<TYPE>::value, TYPE>::type tv(const TYPE &d) {
|
||||
return d;
|
||||
}
|
||||
static const char* tv(const char* d) {
|
||||
return d;
|
||||
}
|
||||
#else
|
||||
template <class TYPE>
|
||||
static const TYPE& tv(const TYPE&d) {
|
||||
return d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
static std::string tv(const QString &d) {
|
||||
return d.toStdString();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#define expect_eq_float(a,b,delta) \
|
||||
do {\
|
||||
if (!((a)>=(b)-delta && (a)<=(b)+delta)) {\
|
||||
std::cout<<std::endl<<"++++++++++"<<__FILE__<<':'<<__LINE__<<'['<<__FUNCTION__<<']'<<"EXPECT_EQ fail.++++++++"<<std::endl;\
|
||||
std::cout<<"expect:"<<TV::tv(b)<<std::endl;\
|
||||
std::cout<<"actual:"<<TV::tv(a)<<std::endl<<std::endl;\
|
||||
++Status::c();\
|
||||
}\
|
||||
}while(false)
|
||||
|
||||
#define EXPECT_EQ(a,b) \
|
||||
do {\
|
||||
if (!((a) == (b))) {\
|
||||
std::cout<<std::endl<<"++++++++++"<<__FILE__<<':'<<__LINE__<<'['<<__FUNCTION__<<']'<<"EXPECT_EQ fail.++++++++"<<std::endl;\
|
||||
std::cout<<"expect:"<<TV::tv(b)<<std::endl;\
|
||||
std::cout<<"actual:"<<TV::tv(a)<<std::endl<<std::endl;\
|
||||
++Status::c();\
|
||||
}\
|
||||
}while(false)
|
||||
|
||||
#define TEST(a, b) static void a##_##b(); static AUTO_ADD_TC __aat__##a##_##b(a##_##b, #a, #b); static void a##_##b()
|
||||
|
||||
#define EXPECT_FLOAT_EQ(a, b) expect_eq_float(a, b, 0.000001)
|
||||
#define EXPECT_DOUBLE_EQ(a, b) expect_eq_float(a, b, 0.000001)
|
||||
|
||||
#define EXPECT_TRUE(a) \
|
||||
do {\
|
||||
if (!(a)) {\
|
||||
std::cout<<std::endl<<"+++++++++++++++++++++++++++"<<__FILE__<<':'<<__LINE__<<'['<<__FUNCTION__<<']'<<"EXPECT_TRUE fail."<<std::endl;\
|
||||
++Status::c();\
|
||||
}\
|
||||
}while(false)
|
||||
|
||||
#define EXPECT_FALSE(a) \
|
||||
do {\
|
||||
if ((a)) {\
|
||||
std::cout<<std::endl<<"+++++++++++++++++++++++++++"<<__FILE__<<':'<<__LINE__<<'['<<__FUNCTION__<<']'<<"EXPECT_FALSE fail."<<std::endl;\
|
||||
++Status::c();\
|
||||
}\
|
||||
}while(false)
|
||||
|
||||
#endif
|
||||
|
||||
45
util/xpack/gtest/makefile
Executable file
45
util/xpack/gtest/makefile
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
ifeq ($(GPP),)
|
||||
GPP=g++
|
||||
endif
|
||||
|
||||
MFLAG=-Wall -Wextra
|
||||
|
||||
INC=-I ../..
|
||||
LIB=-pthread
|
||||
|
||||
# c11 default on
|
||||
ifneq ($(c11),off)
|
||||
MFLAG+=-std=c++11
|
||||
# gtest default off
|
||||
ifeq ($(gtest),on)
|
||||
INC+=-I ../../googletest/googletest/include
|
||||
LIB+=-L ../../googletest/lib -lgtest
|
||||
MFLAG+=-DXGTEST
|
||||
endif
|
||||
endif
|
||||
|
||||
# QT default off
|
||||
ifeq ($(qt),on)
|
||||
INC+=-I /usr/include/qt4 -I /usr/include/qt4/QtCore
|
||||
LIB+=-lQtCore
|
||||
MFLAG+=-DXPACK_SUPPORT_QT
|
||||
endif
|
||||
|
||||
ifneq ($(xout),)
|
||||
MFLAG+=-DXPACK_OUT_TEST
|
||||
endif
|
||||
|
||||
xtest:
|
||||
$(GPP) -o $@ -g $(MFLAG) test.cpp $(INC) $(LIB)
|
||||
@-valgrind --tool=memcheck --leak-check=full ./$@
|
||||
@-rm $@
|
||||
|
||||
test:
|
||||
$(GPP) -o $@ -g $(MFLAG) test.cpp $(INC) $(LIB)
|
||||
@-./$@
|
||||
@-rm $@
|
||||
|
||||
bson:bson_test.cpp
|
||||
$(GPP) -o $@ -g $< -std=c++11 $(INC) $(LIB) $(MFLAG) -lbson-1.0
|
||||
@-valgrind --tool=memcheck --leak-check=full ./$@
|
||||
@-rm $@
|
||||
16
util/xpack/gtest/msvc.make
Executable file
16
util/xpack/gtest/msvc.make
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
SRC=$(wildcard *.cpp)
|
||||
TAR=$(SRC:.cpp=.exe)
|
||||
|
||||
ifneq ($(xout),)
|
||||
MFLAG+=-DXPACK_OUT_TEST
|
||||
endif
|
||||
|
||||
%.exe:%.cpp
|
||||
cl /Fe:${CURDIR}/$@ $< /EHsc /nologo /wd4819 -I ../.. $(MFLAG)
|
||||
@echo ============ run $@ ================
|
||||
@$@
|
||||
|
||||
tar:$(TAR)
|
||||
@echo -------test done-------
|
||||
@-del *.obj
|
||||
@-del *.exe
|
||||
879
util/xpack/gtest/test.cpp
Executable file
879
util/xpack/gtest/test.cpp
Executable file
|
|
@ -0,0 +1,879 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef XGTEST
|
||||
#include<gtest/gtest.h>
|
||||
#else
|
||||
#include "gtest_stub.h"
|
||||
#endif
|
||||
|
||||
#include "xpack/json.h"
|
||||
#include "xpack/xml.h"
|
||||
#include "string.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Base {
|
||||
int a;
|
||||
string b;
|
||||
Base(const int _a=0, const string&_b=""):a(_a), b(_b){}
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(a, b));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(Base, O(a,b));
|
||||
#endif
|
||||
|
||||
|
||||
struct POD {
|
||||
int a;
|
||||
char b[10];
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(a, b));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(POD, O(a,b));
|
||||
#endif
|
||||
|
||||
// ++++++++++++++++++++++BuiltInTypes++++++++++++++++++++++++++++
|
||||
struct BuiltInTypes {
|
||||
signed char sch;
|
||||
char ch;
|
||||
unsigned char uch;
|
||||
short sh;
|
||||
unsigned short ush;
|
||||
int i;
|
||||
unsigned int ui;
|
||||
long l;
|
||||
unsigned long ul;
|
||||
long long ll;
|
||||
unsigned long long ull;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
bool b;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(AF(F(ATTR), sch, "xml:s:ch"), X(F(ATTR), ch, uch, sh, ush), O(i, ui, l, ul, ll, ull, f, d, ld, b));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(BuiltInTypes, AF(F(ATTR), sch, "xml:s:ch"), X(F(ATTR), ch, uch, sh, ush), O(i, ui, l, ul, ll, ull, f, d, ld, b));
|
||||
#endif
|
||||
|
||||
void checkBuiltInTypes(const BuiltInTypes&a, const BuiltInTypes&b) {
|
||||
EXPECT_EQ(a.sch, b.sch);
|
||||
EXPECT_EQ(a.ch, b.ch);
|
||||
EXPECT_EQ(a.uch, b.uch);
|
||||
EXPECT_EQ(a.sh, b.sh);
|
||||
EXPECT_EQ(a.ush, b.ush);
|
||||
EXPECT_EQ(a.i, b.i);
|
||||
EXPECT_EQ(a.ui, b.ui);
|
||||
EXPECT_EQ(a.l, b.l);
|
||||
EXPECT_EQ(a.ul, b.ul);
|
||||
EXPECT_EQ(a.ll, b.ll);
|
||||
EXPECT_EQ(a.ull, b.ull);
|
||||
EXPECT_FLOAT_EQ(a.f, b.f);
|
||||
EXPECT_DOUBLE_EQ(a.d, b.d);
|
||||
EXPECT_DOUBLE_EQ(a.ld, b.ld);
|
||||
EXPECT_TRUE(a.b);
|
||||
}
|
||||
TEST(builtin, types) {
|
||||
BuiltInTypes bt;
|
||||
bt.sch = 0x7f;
|
||||
bt.ch = 0x7f;
|
||||
bt.uch = 0x80;
|
||||
bt.sh = 0x7fff;
|
||||
bt.ush = 0x8000;
|
||||
bt.i = 0x7fffffff;
|
||||
bt.ui = 0x80000000;
|
||||
bt.l = 0x7fffffffffffffff;
|
||||
bt.ul = 0x8000000000000000;
|
||||
bt.ll = bt.l;
|
||||
bt.ull = bt.ul;
|
||||
bt.f = 1.234;
|
||||
bt.d = 9.678;
|
||||
bt.ld = 30.678;
|
||||
bt.b = true;
|
||||
|
||||
string s1 = xpack::json::encode(bt);
|
||||
BuiltInTypes j1;
|
||||
xpack::json::decode(s1, j1);
|
||||
checkBuiltInTypes(j1, bt);
|
||||
|
||||
string s2 = xpack::xml::encode(bt, "root");
|
||||
BuiltInTypes j2;
|
||||
xpack::xml::decode(s2, j2);
|
||||
checkBuiltInTypes(j2, bt);
|
||||
}
|
||||
|
||||
// ++++++++++++++++++++bit field+++++++++++++++++++++++++++
|
||||
struct BitField {
|
||||
short a:8;
|
||||
short b:8;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(B(F(0), a, b));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(BitField, B(F(0), a, b));
|
||||
#endif
|
||||
void checkBitField(const BitField&a, const BitField&b) {
|
||||
EXPECT_EQ(a.a, b.a);
|
||||
EXPECT_EQ(a.b, b.b);
|
||||
}
|
||||
TEST(bitfiled, base) {
|
||||
BitField bf;
|
||||
bf.a = 0x70;
|
||||
bf.b = 0x7f;
|
||||
|
||||
string s1 = xpack::json::encode(bf);
|
||||
BitField j1;
|
||||
xpack::json::decode(s1, j1);
|
||||
checkBitField(j1, bf);
|
||||
|
||||
string s2 = xpack::xml::encode(bf, "root");
|
||||
BitField j2;
|
||||
xpack::xml::decode(s2, j2);
|
||||
checkBitField(j2, bf);
|
||||
}
|
||||
|
||||
// +++++++++++++++++++ enum +++++++++++++++++++++
|
||||
enum Enum1 {
|
||||
E0 = 0,
|
||||
E1 = 1,
|
||||
};
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
enum class Enum2:int64_t {
|
||||
E2 = 2,
|
||||
E3 = 3,
|
||||
};
|
||||
#else
|
||||
enum Enum2 {
|
||||
E2 = 2,
|
||||
E3 = 3,
|
||||
};
|
||||
#endif
|
||||
struct EnumBase {
|
||||
Enum1 e1;
|
||||
Enum2 e2;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
XPACK(O(e1), E(F(0), e2));
|
||||
#else
|
||||
XPACK(E(F(0), e1, e2));
|
||||
#endif
|
||||
};
|
||||
#else
|
||||
};
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
XPACK_OUT(EnumBase, O(e1), E(F(0), e2));
|
||||
#else
|
||||
XPACK_OUT(EnumBase, E(F(0), e1, e2));
|
||||
#endif
|
||||
#endif
|
||||
void checkEnumBase(const EnumBase&a, const EnumBase&b) {
|
||||
EXPECT_EQ(a.e1, b.e1);
|
||||
EXPECT_EQ(a.e2, b.e2);
|
||||
}
|
||||
TEST(enum, base) {
|
||||
EnumBase eb;
|
||||
eb.e1 = E0;
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
eb.e2 = Enum2::E3;
|
||||
#else
|
||||
eb.e2 = E3;
|
||||
#endif
|
||||
|
||||
string s1 = xpack::json::encode(eb);
|
||||
EnumBase j1;
|
||||
xpack::json::decode(s1, j1);
|
||||
checkEnumBase(j1, eb);
|
||||
|
||||
string s2 = xpack::xml::encode(eb, "root");
|
||||
EnumBase j2;
|
||||
xpack::xml::decode(s2, j2);
|
||||
checkEnumBase(j2, eb);
|
||||
}
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
TEST(enum, map) {
|
||||
map<Enum2, int> m;
|
||||
m[Enum2::E2] = 2;
|
||||
m[Enum2::E3] = 3;
|
||||
|
||||
string s1 = xpack::json::encode(m);
|
||||
map<Enum2, int> j1;
|
||||
xpack::json::decode(s1, j1);
|
||||
EXPECT_EQ(j1[Enum2::E2], 2);
|
||||
EXPECT_EQ(j1[Enum2::E3], 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ++++++++++++++++inherit+++++++++++++++++++++++++++++
|
||||
struct InheritBase {
|
||||
int b1;
|
||||
string b2;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(b1, b2));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(InheritBase, O(b1, b2));
|
||||
#endif
|
||||
struct InheritChild:public InheritBase {
|
||||
int c1;
|
||||
string c2;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(I(InheritBase), O(c1, c2));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(InheritChild, I(InheritBase), O(c1, c2));
|
||||
#endif
|
||||
void checkInherit(const InheritChild&a, const InheritChild&b) {
|
||||
EXPECT_EQ(a.b1, b.b1);
|
||||
EXPECT_EQ(a.b2, b.b2);
|
||||
EXPECT_EQ(a.c1, b.c1);
|
||||
EXPECT_EQ(a.c2, b.c2);
|
||||
}
|
||||
TEST(inherit, base) {
|
||||
InheritChild c;
|
||||
c.b1 = 1;
|
||||
c.b2 = "base";
|
||||
c.c1 = 2;
|
||||
c.c2 = "child";
|
||||
|
||||
string s1 = xpack::json::encode(c);
|
||||
InheritChild j1;
|
||||
xpack::json::decode(s1, j1);
|
||||
checkInherit(j1, c);
|
||||
|
||||
string s2 = xpack::xml::encode(c, "root");
|
||||
InheritChild j2;
|
||||
xpack::xml::decode(s2, j2);
|
||||
checkInherit(j2, c);
|
||||
}
|
||||
|
||||
// ++++++++++++++++++++++++array++++++++++++++++++++++++++
|
||||
struct Array {
|
||||
int a[3];
|
||||
char b[3];
|
||||
Base c[3];
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(a, b, c));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(Array, O(a, b, c));
|
||||
#endif
|
||||
void checkArray(const Array&a, const Array&b) {
|
||||
EXPECT_EQ(a.a[0], b.a[0]);
|
||||
EXPECT_EQ(a.a[1], b.a[1]);
|
||||
EXPECT_EQ(a.a[2], b.a[2]);
|
||||
EXPECT_EQ(a.b[0], b.b[0]);
|
||||
EXPECT_EQ(a.b[1], b.b[1]);
|
||||
EXPECT_EQ(a.b[2], b.b[2]);
|
||||
EXPECT_EQ(a.c[0].a, b.c[0].a);
|
||||
EXPECT_EQ(a.c[0].b, b.c[0].b);
|
||||
EXPECT_EQ(a.c[1].a, b.c[1].a);
|
||||
EXPECT_EQ(a.c[1].b, b.c[1].b);
|
||||
EXPECT_EQ(a.c[2].a, b.c[2].a);
|
||||
EXPECT_EQ(a.c[2].b, b.c[2].b);
|
||||
}
|
||||
TEST(array, base) {
|
||||
Array a;
|
||||
a.a[0] = 1;
|
||||
a.a[1] = 2;
|
||||
a.a[2] = 3;
|
||||
a.b[0] = 'g';
|
||||
a.b[1] = 'o';
|
||||
a.b[2] = '\0';
|
||||
a.c[0].a = 11;
|
||||
a.c[1].a = 12;
|
||||
a.c[2].a = 13;
|
||||
a.c[0].b = "hello";
|
||||
a.c[1].b = "good";
|
||||
a.c[1].b = "nice";
|
||||
|
||||
string s1 = xpack::json::encode(a);
|
||||
Array j1;
|
||||
xpack::json::decode(s1, j1);
|
||||
checkArray(j1, a);
|
||||
|
||||
string s2 = xpack::xml::encode(a, "root");
|
||||
Array j2;
|
||||
xpack::xml::decode(s2, j2);
|
||||
checkArray(j2, a);
|
||||
|
||||
char ca[3];
|
||||
xpack::json::decode("\"good\"", ca);
|
||||
EXPECT_TRUE(0==strcmp(ca, "go"));
|
||||
|
||||
int ia[3];
|
||||
xpack::json::decode("[1, 2, 3, 4]", ia);
|
||||
EXPECT_EQ(ia[2], 3);
|
||||
}
|
||||
|
||||
|
||||
// +++++++++++++++ container ++++++++++++++++++++++
|
||||
struct ContainerBase {
|
||||
map<string, int> m;
|
||||
set<int> s;
|
||||
vector<int> v;
|
||||
list<int> l;
|
||||
|
||||
vector<vector<int> > vv;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(m, s, v, l, vv));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(ContainerBase, O(m, s, v, l, vv));
|
||||
#endif
|
||||
void checkContainerBase(ContainerBase&cb) {
|
||||
EXPECT_EQ(cb.m.size(), 2U);
|
||||
EXPECT_EQ(cb.m["a"], 1);
|
||||
EXPECT_EQ(cb.m["b"], 2);
|
||||
EXPECT_EQ(cb.s.size(), 2U);
|
||||
EXPECT_TRUE(cb.s.find(3)!=cb.s.end());
|
||||
EXPECT_TRUE(cb.s.find(4)!=cb.s.end());
|
||||
EXPECT_TRUE(cb.s.find(5)==cb.s.end());
|
||||
EXPECT_EQ(cb.v.size(), 2U);
|
||||
EXPECT_EQ(cb.v[0], 5);
|
||||
EXPECT_EQ(cb.v[1], 6);
|
||||
EXPECT_EQ(cb.l.size(), 2U);
|
||||
EXPECT_EQ(*(cb.l.begin()), 7);
|
||||
EXPECT_EQ(*(++cb.l.begin()), 8);
|
||||
|
||||
EXPECT_EQ(cb.vv.size(), 2U);
|
||||
EXPECT_EQ(cb.vv[0].size(), 2U);
|
||||
EXPECT_EQ(cb.vv[1].size(), 2U);
|
||||
EXPECT_EQ(cb.vv[0][0], 11);
|
||||
EXPECT_EQ(cb.vv[0][1], 12);
|
||||
EXPECT_EQ(cb.vv[1][0], 22);
|
||||
EXPECT_EQ(cb.vv[1][1], 23);
|
||||
}
|
||||
TEST(container, base) {
|
||||
string s = "{\"m\":{\"a\":1, \"b\":2}, \"s\":[3, 4], \"v\":[5,6], \"l\":[7, 8], \"vv\":[[11,12],[22,23]]}";
|
||||
|
||||
ContainerBase cb;
|
||||
xpack::json::decode(s, cb);
|
||||
checkContainerBase(cb);
|
||||
|
||||
string s1 = xpack::json::encode(cb);
|
||||
ContainerBase cb2;
|
||||
xpack::json::decode(s1, cb2);
|
||||
string s2 = xpack::json::encode(cb2);
|
||||
EXPECT_EQ(s1, s2);
|
||||
|
||||
string s3 = xpack::xml::encode(cb, "root");
|
||||
ContainerBase cb3;
|
||||
xpack::xml::decode(s3, cb3);
|
||||
checkContainerBase(cb3);
|
||||
string s4 = xpack::xml::encode(cb3, "root");
|
||||
EXPECT_EQ(s3, s4);
|
||||
}
|
||||
struct ContainerStruct {
|
||||
map<string, Base> m;
|
||||
vector<Base> v;
|
||||
list<Base> l;
|
||||
|
||||
vector<vector<Base> > vv;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(m, v, l, vv));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(ContainerStruct, O(m, v, l, vv));
|
||||
#endif
|
||||
void checkContainerStruct(ContainerStruct&a) {
|
||||
EXPECT_EQ(a.m.size(), 2U);
|
||||
EXPECT_EQ(a.m["a"].a, 1);
|
||||
EXPECT_EQ(a.m["a"].b, "good");
|
||||
EXPECT_EQ(a.m["b"].a, 2);
|
||||
EXPECT_EQ(a.m["b"].b, "nice");
|
||||
|
||||
EXPECT_EQ(a.v.size(), 2U);
|
||||
EXPECT_EQ(a.v[0].a, 3);
|
||||
EXPECT_EQ(a.v[0].b, "hello");
|
||||
EXPECT_EQ(a.v[1].a, 4);
|
||||
EXPECT_EQ(a.v[1].b, "wow");
|
||||
|
||||
list<Base>::const_iterator lit = a.l.begin();
|
||||
EXPECT_EQ(a.l.size(), 2U);
|
||||
EXPECT_EQ(lit->a, 5);
|
||||
EXPECT_EQ(lit->b, "dida");
|
||||
++lit;
|
||||
EXPECT_EQ(lit->a, 6);
|
||||
EXPECT_EQ(lit->b, "haha");
|
||||
|
||||
EXPECT_EQ(a.vv.size(), 2U);
|
||||
EXPECT_EQ(a.vv[0].size(), 1U);
|
||||
EXPECT_EQ(a.vv[1].size(), 2U);
|
||||
EXPECT_EQ(a.vv[0][0].a, 7);
|
||||
EXPECT_EQ(a.vv[0][0].b, "lala");
|
||||
EXPECT_EQ(a.vv[1][0].a, 8);
|
||||
EXPECT_EQ(a.vv[1][0].b, "wawa");
|
||||
EXPECT_EQ(a.vv[1][1].a, 9);
|
||||
EXPECT_EQ(a.vv[1][1].b, "kaka");
|
||||
}
|
||||
TEST(container, struct) {
|
||||
ContainerStruct cb;
|
||||
cb.m["a"] = Base(1, "good");
|
||||
cb.m["b"] = Base(2, "nice");
|
||||
cb.v.push_back(Base(3, "hello"));
|
||||
cb.v.push_back(Base(4, "wow"));
|
||||
cb.l.push_back(Base(5, "dida"));
|
||||
cb.l.push_back(Base(6, "haha"));
|
||||
cb.vv.resize(2);
|
||||
cb.vv[0].resize(1);
|
||||
cb.vv[1].resize(2);
|
||||
cb.vv[0][0].a = 7;
|
||||
cb.vv[0][0].b = "lala";
|
||||
cb.vv[1][0].a = 8;
|
||||
cb.vv[1][0].b = "wawa";
|
||||
cb.vv[1][1].a = 9;
|
||||
cb.vv[1][1].b = "kaka";
|
||||
|
||||
string s1 = xpack::json::encode(cb);
|
||||
ContainerStruct cb1;
|
||||
xpack::json::decode(s1, cb1);
|
||||
checkContainerStruct(cb1);
|
||||
string s2 = xpack::json::encode(cb1);
|
||||
EXPECT_EQ(s1, s2);
|
||||
|
||||
string s3 = xpack::xml::encode(cb, "root");
|
||||
ContainerStruct cb3;
|
||||
xpack::xml::decode(s3, cb3);
|
||||
checkContainerStruct(cb3);
|
||||
string s4 = xpack::xml::encode(cb3, "root");
|
||||
EXPECT_EQ(s3, s4);
|
||||
}
|
||||
|
||||
// +++++++++++++++++++ QT ++++++++++++++++++++
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
struct ContainerQT {
|
||||
QMap<string, Base> m;
|
||||
QVector<Base> v;
|
||||
QList<Base> l;
|
||||
|
||||
QVector<QVector<Base> > vv;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(m, v, l, vv));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(ContainerQT, O(m, v, l, vv));
|
||||
#endif
|
||||
void checkContainerQT(ContainerQT&a) {
|
||||
EXPECT_EQ(a.m.size(), 2);
|
||||
EXPECT_EQ(a.m["a"].a, 1);
|
||||
EXPECT_EQ(a.m["a"].b, "good");
|
||||
EXPECT_EQ(a.m["b"].a, 2);
|
||||
EXPECT_EQ(a.m["b"].b, "nice");
|
||||
|
||||
EXPECT_EQ(a.v.size(), 2);
|
||||
EXPECT_EQ(a.v[0].a, 3);
|
||||
EXPECT_EQ(a.v[0].b, "hello");
|
||||
EXPECT_EQ(a.v[1].a, 4);
|
||||
EXPECT_EQ(a.v[1].b, "wow");
|
||||
|
||||
QList<Base>::const_iterator lit = a.l.begin();
|
||||
EXPECT_EQ(a.l.size(), 2);
|
||||
EXPECT_EQ(lit->a, 5);
|
||||
EXPECT_EQ(lit->b, "dida");
|
||||
++lit;
|
||||
EXPECT_EQ(lit->a, 6);
|
||||
EXPECT_EQ(lit->b, "haha");
|
||||
|
||||
EXPECT_EQ(a.vv.size(), 2);
|
||||
EXPECT_EQ(a.vv[0].size(), 1);
|
||||
EXPECT_EQ(a.vv[1].size(), 2);
|
||||
EXPECT_EQ(a.vv[0][0].a, 7);
|
||||
EXPECT_EQ(a.vv[0][0].b, "lala");
|
||||
EXPECT_EQ(a.vv[1][0].a, 8);
|
||||
EXPECT_EQ(a.vv[1][0].b, "wawa");
|
||||
EXPECT_EQ(a.vv[1][1].a, 9);
|
||||
EXPECT_EQ(a.vv[1][1].b, "kaka");
|
||||
}
|
||||
TEST(container, QT) {
|
||||
ContainerQT cb;
|
||||
cb.m["a"] = Base(1, "good");
|
||||
cb.m["b"] = Base(2, "nice");
|
||||
cb.v.push_back(Base(3, "hello"));
|
||||
cb.v.push_back(Base(4, "wow"));
|
||||
cb.l.push_back(Base(5, "dida"));
|
||||
cb.l.push_back(Base(6, "haha"));
|
||||
cb.vv.resize(2);
|
||||
cb.vv[0].resize(1);
|
||||
cb.vv[1].resize(2);
|
||||
cb.vv[0][0].a = 7;
|
||||
cb.vv[0][0].b = "lala";
|
||||
cb.vv[1][0].a = 8;
|
||||
cb.vv[1][0].b = "wawa";
|
||||
cb.vv[1][1].a = 9;
|
||||
cb.vv[1][1].b = "kaka";
|
||||
|
||||
string s1 = xpack::json::encode(cb);
|
||||
ContainerQT cb1;
|
||||
xpack::json::decode(s1, cb1);
|
||||
checkContainerQT(cb1);
|
||||
string s2 = xpack::json::encode(cb1);
|
||||
EXPECT_EQ(s1, s2);
|
||||
|
||||
string s3 = xpack::xml::encode(cb, "root");
|
||||
ContainerQT cb3;
|
||||
xpack::xml::decode(s3, cb3);
|
||||
checkContainerQT(cb3);
|
||||
string s4 = xpack::xml::encode(cb3, "root");
|
||||
EXPECT_EQ(s3, s4);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ++++++++++++++ xtypes +++++++++++++++++++++
|
||||
struct XtypeUnion {
|
||||
int type;
|
||||
union {
|
||||
POD p;
|
||||
int i;
|
||||
char s[10];
|
||||
};
|
||||
};
|
||||
struct XtypeUnionTop {
|
||||
string name;
|
||||
XtypeUnion un;
|
||||
#ifndef XPACK_OUT_TEST
|
||||
XPACK(O(name, un));
|
||||
};
|
||||
#else
|
||||
};
|
||||
XPACK_OUT(XtypeUnionTop, O(name, un));
|
||||
#endif
|
||||
|
||||
namespace xpack { // must define in namespace xpack
|
||||
|
||||
template<>
|
||||
struct is_xpack_xtype<XtypeUnion> {static bool const value = true;};
|
||||
|
||||
template<class OBJ>
|
||||
bool xpack_xtype_decode(OBJ &obj, XtypeUnion &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
OBJ *o = &obj;
|
||||
o->decode("type", val.type, NULL);
|
||||
switch (val.type) {
|
||||
case 1:
|
||||
o->decode("p", val.p, NULL);
|
||||
break;
|
||||
case 2:
|
||||
o->decode("i", val.i, NULL);
|
||||
break;
|
||||
case 3:
|
||||
o->decode("s", val.s, NULL);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class OBJ>
|
||||
bool xpack_xtype_encode(OBJ &obj, const char*key, const XtypeUnion &val, const Extend *ext) {
|
||||
obj.ObjectBegin(key, ext);
|
||||
obj.encode("type", val.type, NULL);
|
||||
switch (val.type) {
|
||||
case 1:
|
||||
obj.encode("p", val.p, NULL);
|
||||
break;
|
||||
case 2:
|
||||
obj.encode("i", val.i, NULL);
|
||||
break;
|
||||
case 3:
|
||||
obj.encode("s", val.s, NULL);
|
||||
break;
|
||||
}
|
||||
obj.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void checkXtypesUnion(const XtypeUnionTop &xt, bool cn) {
|
||||
if (cn) {
|
||||
EXPECT_EQ(xt.name, "hello");
|
||||
}
|
||||
|
||||
if (xt.un.type == 1) {
|
||||
EXPECT_EQ(xt.un.p.a, 10);
|
||||
EXPECT_TRUE(0 == strcmp(xt.un.p.b, "good"));
|
||||
} else if (xt.un.type == 2) {
|
||||
EXPECT_EQ(xt.un.i, 20);
|
||||
} else if (xt.un.type == 3) {
|
||||
EXPECT_TRUE(0 == strcmp(xt.un.s, "nice"));
|
||||
} else {
|
||||
EXPECT_EQ(xt.un.type, 1);
|
||||
}
|
||||
}
|
||||
TEST(xtypes, union) {
|
||||
XtypeUnionTop xt;
|
||||
xt.name = "hello";
|
||||
xt.un.type = 1;
|
||||
xt.un.p.a = 10;
|
||||
strcpy(xt.un.p.b, "good");
|
||||
|
||||
string s = xpack::json::encode(xt);
|
||||
XtypeUnionTop xt1;
|
||||
xpack::json::decode(s, xt1);
|
||||
checkXtypesUnion(xt1, true);
|
||||
|
||||
s = xpack::xml::encode(xt, "root");
|
||||
XtypeUnionTop xt2;
|
||||
xpack::xml::decode(s, xt2);
|
||||
checkXtypesUnion(xt2, true);
|
||||
|
||||
s = xpack::json::encode(xt.un);
|
||||
XtypeUnionTop xt3;
|
||||
xpack::json::decode(s, xt3.un);
|
||||
checkXtypesUnion(xt3, false);
|
||||
|
||||
s = xpack::xml::encode(xt.un, "root");
|
||||
XtypeUnionTop xt4;
|
||||
xpack::xml::decode(s, xt4.un);
|
||||
checkXtypesUnion(xt4, false);
|
||||
}
|
||||
|
||||
// +++++++++++++++++ custom +++++++++++++++++
|
||||
struct Custom {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
XPACK(O(a, b), C(hex, F(0), c));
|
||||
};
|
||||
|
||||
namespace xpack {
|
||||
template <class OBJ>
|
||||
bool hex_encode(OBJ &obj, const Custom&c, const char*key, const int &i, const Extend *ext) {
|
||||
(void)c;
|
||||
stringstream ss;
|
||||
ss<<"0x"<<std::hex<<i;
|
||||
return obj.encode(key, ss.str(), ext);
|
||||
}
|
||||
template <class OBJ>
|
||||
bool hex_decode(OBJ &obj, Custom&c, const char*key, int &i, const Extend *ext) {
|
||||
(void)c;
|
||||
string s;
|
||||
if (!obj.decode(key, s, ext)) {
|
||||
return false;
|
||||
}
|
||||
stringstream ss;
|
||||
ss<<std::hex<<s;
|
||||
ss>>i;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
TEST(custom, hex) {
|
||||
Custom c;
|
||||
c.a = 1;
|
||||
c.b = 2;
|
||||
c.c = 0xe;
|
||||
string s = xpack::json::encode(c);
|
||||
EXPECT_EQ(s, "{\"a\":1,\"b\":2,\"c\":\"0xe\"}");
|
||||
|
||||
Custom c1;
|
||||
xpack::json::decode(s, c1);
|
||||
EXPECT_EQ(c1.a, 1);
|
||||
EXPECT_EQ(c1.b, 2);
|
||||
EXPECT_EQ(c1.c, 0xe);
|
||||
}
|
||||
|
||||
// +++++++++++++++++ flags ++++++++++++++++++
|
||||
struct FlagEN {
|
||||
int a;
|
||||
string b;
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
shared_ptr<int> c;
|
||||
#else
|
||||
int c;
|
||||
#endif
|
||||
XPACK(X(F(EN), a, b, c));
|
||||
FlagEN(){c=0;}
|
||||
};
|
||||
TEST(flags, EN) {
|
||||
FlagEN fe;
|
||||
fe.a = 1;
|
||||
|
||||
string s = xpack::json::encode(fe);
|
||||
EXPECT_EQ(s, "{\"a\":1,\"b\":null,\"c\":null}");
|
||||
|
||||
FlagEN f1;
|
||||
xpack::json::decode(s, f1);
|
||||
EXPECT_EQ(f1.a, 1);
|
||||
EXPECT_EQ(f1.b, "");
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
EXPECT_EQ(f1.c.get(), (int*)NULL);
|
||||
#else
|
||||
EXPECT_EQ(f1.c, 0);
|
||||
#endif
|
||||
}
|
||||
struct FlagM {
|
||||
int a;
|
||||
string b;
|
||||
XPACK(O(a), M(b));
|
||||
};
|
||||
TEST(flags, M) {
|
||||
string s = "{\"a\":1}";
|
||||
bool except = false;
|
||||
try {
|
||||
FlagM f;
|
||||
xpack::json::decode(s, f);
|
||||
} catch(...) {
|
||||
except = true;
|
||||
}
|
||||
EXPECT_TRUE(except);
|
||||
}
|
||||
struct FlagATTR {
|
||||
int a;
|
||||
string b;
|
||||
XPACK(O(a), X(F(ATTR), b));
|
||||
};
|
||||
TEST(flags, ATTR) {
|
||||
FlagATTR f;
|
||||
f.a = 1;
|
||||
f.b = "hello";
|
||||
string s = xpack::xml::encode(f, "root");
|
||||
EXPECT_EQ(s, "<root b=\"hello\"><a>1</a></root>");
|
||||
|
||||
FlagATTR f1;
|
||||
xpack::xml::decode(s, f1);
|
||||
EXPECT_EQ(f1.a, 1);
|
||||
EXPECT_EQ(f1.b, "hello");
|
||||
}
|
||||
struct FlagVectorLabel {
|
||||
vector<int> a;
|
||||
vector<int> b;
|
||||
vector<int> c;
|
||||
XPACK(O(a), A(b, "xml:b,sbs", c, "xml:c,vl@x"));
|
||||
};
|
||||
TEST(flags, vectorlabel) {
|
||||
FlagVectorLabel f;
|
||||
f.a.push_back(1);
|
||||
f.a.push_back(2);
|
||||
f.b.push_back(3);
|
||||
f.b.push_back(4);
|
||||
f.c.push_back(5);
|
||||
f.c.push_back(6);
|
||||
|
||||
string s = xpack::xml::encode(f, "root");
|
||||
EXPECT_EQ(s, "<root><a><a>1</a><a>2</a></a><b>3</b><b>4</b><c><x>5</x><x>6</x></c></root>");
|
||||
|
||||
FlagVectorLabel f1;
|
||||
xpack::xml::decode(s, f1);
|
||||
EXPECT_EQ(f1.a.size(), 2U);
|
||||
EXPECT_EQ(f1.a[0], 1);
|
||||
EXPECT_EQ(f1.a[1], 2);
|
||||
EXPECT_EQ(f1.b.size(), 2U);
|
||||
EXPECT_EQ(f1.b[0], 3);
|
||||
EXPECT_EQ(f1.b[1], 4);
|
||||
EXPECT_EQ(f1.c.size(), 2U);
|
||||
EXPECT_EQ(f1.c[0], 5);
|
||||
EXPECT_EQ(f1.c[1], 6);
|
||||
}
|
||||
|
||||
TEST(jsondata, memory) {
|
||||
xpack::JsonData *jd = new xpack::JsonData;
|
||||
|
||||
xpack::json::decode("[0, 1, 2, 3]", *jd);
|
||||
EXPECT_TRUE(jd->IsArray());
|
||||
EXPECT_EQ(jd->Size(), 4U);
|
||||
EXPECT_TRUE((*jd)[(size_t)0].IsNumber());
|
||||
EXPECT_EQ((*jd)[1].Get<int64_t>(), 1);
|
||||
|
||||
xpack::JsonData s = *jd;
|
||||
delete jd;
|
||||
|
||||
EXPECT_TRUE(s.IsArray());
|
||||
EXPECT_TRUE(s[(size_t)0].IsNumber());
|
||||
EXPECT_EQ(s[1].Get<int64_t>(), 1);
|
||||
}
|
||||
|
||||
// ++++++++++++++++++bug history+++++++++++++++++++++++
|
||||
TEST(bughis, notexists) {
|
||||
Base b(9, "");
|
||||
xpack::json::decode("{\"a\":1}", b);
|
||||
EXPECT_EQ(b.a, 1);
|
||||
|
||||
Base b1(10, "");
|
||||
xpack::xml::decode("<root><a>1</a></root>", b1);
|
||||
EXPECT_EQ(b1.a, 1);
|
||||
}
|
||||
|
||||
struct OmitEmpty{
|
||||
int a;
|
||||
vector<int> b;
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
shared_ptr<Base> c;
|
||||
#else
|
||||
Base c;
|
||||
#endif
|
||||
XPACK(X(F(OE), a, b, c));
|
||||
};
|
||||
TEST(bughis, omitempty) {
|
||||
OmitEmpty oe;
|
||||
oe.a = 0;
|
||||
oe.b.push_back(0);
|
||||
oe.b.push_back(0);
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
oe.c.reset(new Base(0, ""));
|
||||
#endif
|
||||
|
||||
string s = xpack::json::encode(oe);
|
||||
EXPECT_EQ(s, "{\"b\":[0,0],\"c\":{\"a\":0,\"b\":\"\"}}");
|
||||
s = xpack::xml::encode(oe, "root");
|
||||
EXPECT_EQ(s, "<root><b><b>0</b><b>0</b></b><c><a>0</a><b/></c></root>");
|
||||
|
||||
oe.b.clear();
|
||||
oe.a = 1;
|
||||
s = xpack::json::encode(oe);
|
||||
EXPECT_EQ(s, "{\"a\":1,\"c\":{\"a\":0,\"b\":\"\"}}");
|
||||
s = xpack::xml::encode(oe, "root");
|
||||
EXPECT_EQ(s, "<root><a>1</a><c><a>0</a><b/></c></root>");
|
||||
}
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
struct SharedPtrNull{
|
||||
shared_ptr<xpack::JsonData> jd;
|
||||
XPACK(O(jd));
|
||||
};
|
||||
TEST(bughis, shared_ptr_null) {
|
||||
SharedPtrNull sn;
|
||||
|
||||
xpack::json::decode("{\"jd\":null}", sn);
|
||||
EXPECT_FALSE(sn.jd);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#ifdef XGTEST
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
TC_CONTAINER::RUN();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
63
util/xpack/json.h
Executable file
63
util/xpack/json.h
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_JSON_H
|
||||
#define __X_PACK_JSON_H
|
||||
|
||||
#include "json_decoder.h"
|
||||
#include "json_encoder.h"
|
||||
#if defined(X_PACK_SUPPORT_CXX0X) || defined (_GNU_SOURCE)
|
||||
#include "json_data.h"
|
||||
#endif
|
||||
#include "xpack.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class json {
|
||||
public:
|
||||
template <class T>
|
||||
static void decode(const std::string &data, T &val) {
|
||||
JsonDecoder de;
|
||||
de.decode(data, val);
|
||||
}
|
||||
template <class T>
|
||||
static void decode(const rapidjson::Value &data, T &val) {
|
||||
JsonNode node(&data);
|
||||
XDecoder<JsonNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
}
|
||||
template <class T>
|
||||
static void decode_file(const std::string &file_name, T &val) {
|
||||
JsonDecoder de;
|
||||
de.decode_file(file_name, val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string encode(const T &val) {
|
||||
JsonEncoder en;
|
||||
return en.encode(val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string encode(const T &val, int flag, int indentCount, char indentChar) {
|
||||
(void)flag;
|
||||
JsonEncoder en(indentCount, indentChar);
|
||||
return en.encode(val);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
115
util/xpack/json_data.h
Executable file
115
util/xpack/json_data.h
Executable file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_JSON_DATA_H
|
||||
#define __X_PACK_JSON_DATA_H
|
||||
|
||||
|
||||
#include "rapidjson_custom.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "util.h"
|
||||
#include "traits.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
// wrapper for rapidjson::Value.
|
||||
// If we use other json parser someday, users won't have to modify the code.
|
||||
// Most of the code is copied from rapidjson.
|
||||
enum JsonType {
|
||||
kNullType = 0, //!< null
|
||||
kFalseType = 1, //!< false
|
||||
kTrueType = 2, //!< true
|
||||
kObjectType = 3, //!< object
|
||||
kArrayType = 4, //!< array
|
||||
kStringType = 5, //!< string
|
||||
kNumberType = 6 //!< number
|
||||
};
|
||||
|
||||
class JsonData {
|
||||
friend class JsonNode;
|
||||
friend class JsonWriter;
|
||||
public:
|
||||
JsonData():current(NULL){}
|
||||
|
||||
// check is valid JsonData
|
||||
operator bool() const {
|
||||
return NULL != current;
|
||||
}
|
||||
JsonType Type() const {
|
||||
if (NULL != current) {
|
||||
return static_cast<JsonType>(current->GetType());
|
||||
}
|
||||
return kNullType; // ?
|
||||
}
|
||||
bool IsNull() const { return NULL==current||current->IsNull(); }
|
||||
bool IsBool() const { return NULL!=current && current->IsBool(); }
|
||||
bool IsObject() const { return NULL!=current && current->IsObject(); }
|
||||
bool IsArray() const { return NULL!=current && current->IsArray(); }
|
||||
bool IsNumber() const { return NULL!=current && current->IsNumber(); }
|
||||
bool IsDouble() const { return NULL!=current && current->IsDouble(); }
|
||||
bool IsString() const { return NULL!=current && current->IsString(); }
|
||||
size_t Size() const {return (size_t)current->Size();}
|
||||
|
||||
JsonData operator [](const char *key) const {
|
||||
if (NULL != current && current->IsObject()) {
|
||||
rapidjson::Value::ConstMemberIterator iter = current->FindMember(key);
|
||||
if (iter != current->MemberEnd()) {
|
||||
return JsonData(&iter->value);
|
||||
} // no exception ?
|
||||
}
|
||||
return JsonData();
|
||||
}
|
||||
JsonData operator [](size_t index) const {
|
||||
if (NULL != current && current->IsArray() && index < (size_t)current->Size()) {
|
||||
return JsonData(&(*current)[(rapidjson::SizeType)index]);
|
||||
}
|
||||
return JsonData();
|
||||
}
|
||||
|
||||
std::string String() const; // Implementation in json_encoder.h
|
||||
|
||||
template <typename T> // For base byte(integer/float/double/bool/std::string), implementation in json_decoder.h
|
||||
T Get() const;
|
||||
|
||||
template <typename T> // struct, implementation in json_decoder.h
|
||||
bool Get(T &val) const;
|
||||
|
||||
private:
|
||||
JsonData(const rapidjson::Value*v):current(v){}
|
||||
|
||||
void reset(const rapidjson::Value *v) {
|
||||
node.reset();
|
||||
allocator.reset();
|
||||
current = NULL;
|
||||
if (NULL != v) {
|
||||
if (v->IsNull()) {
|
||||
node.reset(new rapidjson::Value());
|
||||
} else {
|
||||
allocator.reset(new rapidjson::MemoryPoolAllocator<>());
|
||||
node.reset(new rapidjson::Value(*v, *allocator, true));
|
||||
}
|
||||
current = node.get();
|
||||
}
|
||||
}
|
||||
x_shared_ptr<rapidjson::MemoryPoolAllocator<> > allocator;
|
||||
x_shared_ptr<rapidjson::Value> node; // release node first
|
||||
|
||||
const rapidjson::Value* current;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
218
util/xpack/json_decoder.h
Executable file
218
util/xpack/json_decoder.h
Executable file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_JSON_DECODER_H
|
||||
#define __X_PACK_JSON_DECODER_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "rapidjson_custom.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
#include "xdecoder.h"
|
||||
#include "json_data.h"
|
||||
|
||||
|
||||
namespace xpack {
|
||||
|
||||
|
||||
class JsonNode {
|
||||
typedef XDecoder<JsonNode> decoder;
|
||||
public:
|
||||
typedef rapidjson::Value::ConstMemberIterator Iterator;
|
||||
|
||||
JsonNode(const rapidjson::Value* val=NULL):v(val){}
|
||||
|
||||
// convert JsonData to JsonNode
|
||||
// The life cycle of jd cannot be shorter than JsonNode
|
||||
JsonNode(const JsonData&jd):v(jd.current){}
|
||||
|
||||
inline static const char * Name() {
|
||||
return "json";
|
||||
}
|
||||
operator bool() const {
|
||||
return v != NULL;
|
||||
}
|
||||
bool IsNull() const {
|
||||
return v!=NULL && v->IsNull();
|
||||
}
|
||||
JsonNode Find(decoder&de, const char*key, const Extend *ext) const {
|
||||
(void)ext;
|
||||
if (v->IsNull()) {
|
||||
return JsonNode();
|
||||
} else if (!v->IsObject()) {
|
||||
de.decode_exception("not object", NULL);
|
||||
}
|
||||
rapidjson::Value::ConstMemberIterator iter = v->FindMember(key);
|
||||
if (iter != v->MemberEnd()) {
|
||||
return JsonNode(&iter->value);
|
||||
} else {
|
||||
return JsonNode();
|
||||
}
|
||||
}
|
||||
size_t Size(decoder&de) const {
|
||||
if (v->IsNull()) {
|
||||
return 0;
|
||||
} else if (!v->IsArray()) {
|
||||
de.decode_exception("not array", NULL);
|
||||
}
|
||||
return (size_t)v->Size();
|
||||
}
|
||||
JsonNode At(size_t index) const { // no exception
|
||||
return JsonNode(&(*v)[(rapidjson::SizeType)index]);
|
||||
}
|
||||
JsonNode Next(decoder&de, const JsonNode&parent, Iterator&iter, std::string&key) const {
|
||||
if (!parent.v->IsObject()) {
|
||||
de.decode_exception("not object", NULL);
|
||||
}
|
||||
|
||||
if (v != parent.v) {
|
||||
++iter;
|
||||
} else {
|
||||
iter = parent.v->MemberBegin();
|
||||
}
|
||||
|
||||
if (iter != parent.v->MemberEnd()) {
|
||||
key = iter->name.GetString();
|
||||
return JsonNode(&iter->value);
|
||||
}
|
||||
|
||||
return JsonNode();
|
||||
}
|
||||
|
||||
bool Get(decoder&de, std::string&val, const Extend*ext) {
|
||||
(void)ext;
|
||||
if (v->IsString()) {
|
||||
val = std::string(v->GetString(), v->GetStringLength());
|
||||
} else if (!v->IsNull()) {
|
||||
de.decode_exception("not string", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Get(decoder&de, bool &val, const Extend*ext) {
|
||||
(void)ext;
|
||||
if (v->IsBool()) {
|
||||
val = v->GetBool();
|
||||
} else if (v->IsInt64()) {
|
||||
val = (0 != (v->GetInt64()));
|
||||
} else if (v->IsNull()) {
|
||||
val = false;
|
||||
} else {
|
||||
de.decode_exception("not bool or integer", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)ext;
|
||||
if (v->IsInt()) {
|
||||
val = (T)v->GetInt();
|
||||
} else if (v->IsUint()) {
|
||||
val = (T)v->GetUint();
|
||||
} else if (v->IsInt64()) {
|
||||
val = (T)v->GetInt64();
|
||||
} else if (v->IsUint64()) {
|
||||
val = (T)v->GetUint64();
|
||||
} else if (v->IsNull()) {
|
||||
val = 0;
|
||||
} else {
|
||||
de.decode_exception("not integer", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)ext;
|
||||
if (v->IsNumber()) {
|
||||
val = (T)v->GetDouble();
|
||||
} else if (v->IsNull()) {
|
||||
val = 0;
|
||||
} else {
|
||||
de.decode_exception("not number", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////// for JsonData ///////////////////////
|
||||
bool decode_type_spec(JsonData& val, const Extend *ext) {
|
||||
(void)ext;
|
||||
val.reset(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const rapidjson::Value* v;
|
||||
rapidjson::Value::ConstMemberIterator iter;
|
||||
};
|
||||
|
||||
class JsonDecoder {
|
||||
public:
|
||||
template <class T>
|
||||
bool decode(const std::string&str, T&val) {
|
||||
rapidjson::Document doc;
|
||||
if (this->parse(str, doc)) {
|
||||
JsonNode node(&doc);
|
||||
return XDecoder<JsonNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
bool decode_file(const std::string&fname, T&val) {
|
||||
std::string data;
|
||||
bool ret = Util::readfile(fname, data);
|
||||
if (ret) {
|
||||
ret = this->decode(data, val);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
bool parse(const std::string&data, rapidjson::Document &doc) {
|
||||
std::string err;
|
||||
|
||||
const unsigned int parseFlags = rapidjson::kParseNanAndInfFlag;
|
||||
doc.Parse<parseFlags>(data.data(), data.length());
|
||||
|
||||
if (doc.HasParseError()) {
|
||||
size_t offset = doc.GetErrorOffset();
|
||||
std::string parse_err(rapidjson::GetParseError_En(doc.GetParseError()));
|
||||
std::string err_data = data.substr(offset, 32);
|
||||
err = "Parse json fail. err="+parse_err+". offset="+err_data;
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// /////////////// JsonData ///////////////////
|
||||
template<>struct is_xpack_type_spec<JsonNode, JsonData> {static bool const value = true;};
|
||||
|
||||
template <typename T>
|
||||
inline T JsonData::Get() const {
|
||||
JsonNode node(*this);
|
||||
T t;
|
||||
XDecoder<JsonNode>(NULL, (const char*)NULL, node).decode(t, NULL);
|
||||
return t;
|
||||
}
|
||||
template <typename T>
|
||||
inline bool JsonData::Get(T&val) const {
|
||||
JsonNode node(*this);
|
||||
return XDecoder<JsonNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
294
util/xpack/json_encoder.h
Executable file
294
util/xpack/json_encoder.h
Executable file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_JSON_ENCODER_H
|
||||
#define __X_PACK_JSON_ENCODER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rapidjson_custom.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
#include "xencoder.h"
|
||||
#include "json_data.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class JsonWriter:private noncopyable {
|
||||
typedef rapidjson::StringBuffer JSON_WRITER_BUFFER;
|
||||
typedef rapidjson::Writer<rapidjson::StringBuffer> JSON_WRITER_WRITER;
|
||||
typedef rapidjson::PrettyWriter<rapidjson::StringBuffer> JSON_WRITER_PRETTY;
|
||||
|
||||
friend class XEncoder<JsonWriter>;
|
||||
friend class JsonEncoder;
|
||||
|
||||
const static bool support_null = true;
|
||||
public:
|
||||
JsonWriter(int indentCount = -1, char indentChar = ' ', int maxDecimalPlaces = -1) {
|
||||
_buf = new JSON_WRITER_BUFFER;
|
||||
if (indentCount < 0) {
|
||||
_writer = new JSON_WRITER_WRITER(*_buf);
|
||||
if (maxDecimalPlaces > 0) {
|
||||
_writer->SetMaxDecimalPlaces(maxDecimalPlaces);
|
||||
}
|
||||
_pretty = NULL;
|
||||
} else {
|
||||
_pretty = new JSON_WRITER_PRETTY(*_buf);
|
||||
_pretty->SetIndent(indentChar, indentCount);
|
||||
if (maxDecimalPlaces > 0) {
|
||||
_pretty->SetMaxDecimalPlaces(maxDecimalPlaces);
|
||||
}
|
||||
_writer = NULL;
|
||||
}
|
||||
}
|
||||
~JsonWriter() {
|
||||
if (NULL != _buf) {
|
||||
delete _buf;
|
||||
_buf = NULL;
|
||||
}
|
||||
if (NULL != _writer) {
|
||||
delete _writer;
|
||||
_writer = NULL;
|
||||
}
|
||||
if (NULL != _pretty) {
|
||||
delete _pretty;
|
||||
_pretty = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
inline static const char *Name() {
|
||||
return "json";
|
||||
}
|
||||
inline const char *IndexKey(size_t index) {
|
||||
(void)index;
|
||||
return NULL;
|
||||
}
|
||||
std::string String() {
|
||||
return _buf->GetString();
|
||||
}
|
||||
|
||||
void ArrayBegin(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->StartArray();
|
||||
} else {
|
||||
if (Extend::Flag(ext) & X_PACK_FLAG_SL) {
|
||||
_pretty->SetFormatOptions(rapidjson::kFormatSingleLineArray);
|
||||
}
|
||||
_pretty->StartArray();
|
||||
}
|
||||
}
|
||||
void ArrayEnd(const char *key, const Extend *ext) {
|
||||
(void)key;
|
||||
(void)ext;
|
||||
if (NULL != _writer) {
|
||||
_writer->EndArray();
|
||||
} else {
|
||||
_pretty->EndArray();
|
||||
if (Extend::Flag(ext) & X_PACK_FLAG_SL) {
|
||||
_pretty->SetFormatOptions(rapidjson::kFormatDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ObjectBegin(const char *key, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->StartObject();
|
||||
} else {
|
||||
_pretty->StartObject();
|
||||
}
|
||||
}
|
||||
void ObjectEnd(const char *key, const Extend *ext) {
|
||||
(void)key;
|
||||
(void)ext;
|
||||
if (NULL != _writer) {
|
||||
_writer->EndObject();
|
||||
} else {
|
||||
_pretty->EndObject();
|
||||
}
|
||||
}
|
||||
bool WriteNull(const char*key, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->Null();
|
||||
} else {
|
||||
_pretty->Null();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool encode_bool(const char*key, const bool&val, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->Bool(val);
|
||||
} else {
|
||||
_pretty->Bool(val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const char*val, size_t length, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->String(val, length);
|
||||
} else {
|
||||
_pretty->String(val, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool encode_string(const char*key, const std::string&val, const Extend *ext) {
|
||||
return this->encode_string(key, val.data(), val.length(), ext);
|
||||
}
|
||||
template <typename T>
|
||||
typename x_enable_if<numeric<T>::is_integer && numeric<T>::is_signed, bool>::type encode_number(const char*key, const T&val, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->Int64((int64_t)val);
|
||||
} else {
|
||||
_pretty->Int64((int64_t)val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
typename x_enable_if<numeric<T>::is_integer && !numeric<T>::is_signed, bool>::type encode_number(const char*key, const T&val, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->Uint64((uint64_t)val);
|
||||
} else {
|
||||
_pretty->Uint64((uint64_t)val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type encode_number(const char*key, const T&val, const Extend *ext) {
|
||||
(void)ext;
|
||||
xpack_set_key(key);
|
||||
if (NULL != _writer) {
|
||||
_writer->Double((double)val);
|
||||
} else {
|
||||
_pretty->Double((double)val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// JsonData
|
||||
bool encode_type_spec(const char*key, const JsonData&val, const Extend *ext) {
|
||||
if (val.current == NULL) {
|
||||
return false;
|
||||
}
|
||||
return this->encode_json_value(key, *val.current, ext);
|
||||
}
|
||||
|
||||
bool encode_json_value(const char*key, const rapidjson::Value& val, const Extend *ext) {
|
||||
switch (val.GetType()){
|
||||
case rapidjson::kNullType:
|
||||
return this->WriteNull(key, ext);
|
||||
case rapidjson::kFalseType:
|
||||
case rapidjson::kTrueType:
|
||||
return this->encode_bool(key, val.GetBool(), ext);
|
||||
case rapidjson::kStringType:
|
||||
return this->encode_string(key, val.GetString(), (size_t)val.GetStringLength(), ext);
|
||||
case rapidjson::kNumberType:
|
||||
if (val.IsDouble()) {
|
||||
return this->encode_number(key, val.GetDouble(), ext);
|
||||
} else {
|
||||
return this->encode_number(key, val.GetInt64(), ext);
|
||||
}
|
||||
case rapidjson::kObjectType:
|
||||
this->ObjectBegin(key, ext);
|
||||
for (rapidjson::Value::ConstMemberIterator iter = val.MemberBegin(); iter!=val.MemberEnd(); ++iter) {
|
||||
this->encode_json_value(iter->name.GetString(), iter->value, ext);
|
||||
}
|
||||
this->ObjectEnd(key, ext);
|
||||
break;
|
||||
case rapidjson::kArrayType:{
|
||||
this->ArrayBegin(key, ext);
|
||||
size_t max = (size_t)val.Size();
|
||||
for (size_t i = 0; i<max; ++i) {
|
||||
this->encode_json_value(NULL, val[(rapidjson::SizeType)i], ext);
|
||||
}
|
||||
this->ArrayEnd(key, ext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void xpack_set_key(const char*key) { // openssl defined set_key macro, so we named it xpack_set_key
|
||||
if (NULL!=key && key[0]!='\0') {
|
||||
if (NULL != _writer) {
|
||||
_writer->Key(key);
|
||||
} else {
|
||||
_pretty->Key(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSON_WRITER_BUFFER* _buf;
|
||||
JSON_WRITER_WRITER* _writer;
|
||||
JSON_WRITER_PRETTY* _pretty;
|
||||
};
|
||||
|
||||
class JsonEncoder {
|
||||
public:
|
||||
JsonEncoder() {
|
||||
indentCount = -1;
|
||||
indentChar = ' ';
|
||||
maxDecimalPlaces = -1;
|
||||
}
|
||||
JsonEncoder(int _indentCount, char _indentChar, int _maxDecimalPlaces = -1) { // compat
|
||||
indentCount = _indentCount;
|
||||
indentChar = _indentChar;
|
||||
maxDecimalPlaces = _maxDecimalPlaces;
|
||||
}
|
||||
|
||||
void SetMaxDecimalPlaces(int _maxDecimalPlaces) {
|
||||
maxDecimalPlaces = _maxDecimalPlaces;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode(const T&val) {
|
||||
JsonWriter wr(indentCount, indentChar, maxDecimalPlaces);
|
||||
XEncoder<JsonWriter> en(wr);
|
||||
en.encode(NULL, val, NULL);
|
||||
return wr.String();
|
||||
}
|
||||
|
||||
private:
|
||||
int indentCount;
|
||||
char indentChar;
|
||||
int maxDecimalPlaces;
|
||||
};
|
||||
|
||||
// //////////////// JsonData ///////////////////////
|
||||
template<>struct is_xpack_type_spec<JsonWriter, JsonData> {static bool const value = true;};
|
||||
|
||||
inline std::string JsonData::String() const {
|
||||
JsonEncoder en;
|
||||
return en.encode(*this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
503
util/xpack/l1l2_expand.h
Executable file
503
util/xpack/l1l2_expand.h
Executable file
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_L1_L2_EXPAND_H
|
||||
#define __X_L1_L2_EXPAND_H
|
||||
|
||||
|
||||
// expand macro depend on parameters number
|
||||
#define X_PACK_COUNT(LEVEL, ACTION, _99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,N,...) LEVEL##N
|
||||
#define X_PACK_EXPAND(...) __VA_ARGS__
|
||||
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
|
||||
#define X_PACK_N(LEVEL, ACTION, ...) X_PACK_COUNT(LEVEL, ACTION, __VA_ARGS__, _99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1) (ACTION, __VA_ARGS__)
|
||||
|
||||
#define X_PACK_N2(LEVEL, ACTION, ARG, ...) X_PACK_COUNT(LEVEL, ACTION, __VA_ARGS__, _99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1) (ACTION, ARG, __VA_ARGS__)
|
||||
|
||||
#define X_PACK_L1_DEF(ACT, M) ACT(M) // here will expand to ACT(O(xxx)), ACT(A(a,x)), ACT(M(xxx))
|
||||
#define X_PACK_L1_1(ACT, M) X_PACK_L1_DEF(ACT, M)
|
||||
#define X_PACK_L1_2(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_1(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_3(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_2(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_4(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_3(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_5(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_4(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_6(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_5(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_7(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_6(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_8(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_7(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_9(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_8(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_10(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_9(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_11(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_10(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_12(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_11(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_13(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_12(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_14(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_13(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_15(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_14(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_16(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_15(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_17(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_16(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_18(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_17(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_19(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_18(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_20(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_19(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_21(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_20(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_22(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_21(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_23(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_22(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_24(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_23(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_25(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_24(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_26(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_25(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_27(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_26(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_28(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_27(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_29(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_28(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_30(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_29(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_31(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_30(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_32(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_31(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_33(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_32(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_34(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_33(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_35(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_34(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_36(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_35(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_37(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_36(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_38(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_37(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_39(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_38(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_40(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_39(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_41(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_40(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_42(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_41(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_43(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_42(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_44(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_43(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_45(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_44(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_46(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_45(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_47(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_46(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_48(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_47(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_49(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_48(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_50(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_49(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_51(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_50(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_52(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_51(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_53(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_52(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_54(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_53(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_55(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_54(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_56(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_55(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_57(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_56(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_58(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_57(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_59(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_58(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_60(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_59(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_61(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_60(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_62(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_61(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_63(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_62(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_64(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_63(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_65(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_64(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_66(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_65(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_67(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_66(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_68(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_67(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_69(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_68(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_70(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_69(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_71(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_70(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_72(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_71(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_73(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_72(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_74(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_73(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_75(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_74(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_76(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_75(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_77(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_76(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_78(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_77(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_79(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_78(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_80(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_79(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_81(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_80(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_82(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_81(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_83(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_82(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_84(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_83(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_85(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_84(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_86(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_85(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_87(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_86(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_88(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_87(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_89(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_88(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_90(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_89(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_91(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_90(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_92(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_91(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_93(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_92(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_94(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_93(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_95(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_94(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_96(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_95(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_97(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_96(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_98(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_97(ACT, __VA_ARGS__)
|
||||
#define X_PACK_L1_99(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_98(ACT, __VA_ARGS__)
|
||||
|
||||
#define X_PACK_L2_DEF(ACT, ARG, M) ACT(ARG, M)
|
||||
#define X_PACK_L2_1(ACT, ARG, M) X_PACK_L2_DEF(ACT, ARG, M)
|
||||
#define X_PACK_L2_2(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_1(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_3(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_2(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_4(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_3(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_5(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_4(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_6(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_5(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_7(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_6(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_8(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_7(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_9(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_8(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_10(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_9(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_11(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_10(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_12(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_11(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_13(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_12(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_14(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_13(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_15(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_14(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_16(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_15(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_17(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_16(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_18(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_17(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_19(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_18(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_20(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_19(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_21(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_20(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_22(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_21(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_23(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_22(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_24(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_23(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_25(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_24(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_26(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_25(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_27(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_26(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_28(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_27(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_29(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_28(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_30(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_29(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_31(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_30(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_32(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_31(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_33(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_32(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_34(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_33(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_35(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_34(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_36(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_35(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_37(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_36(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_38(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_37(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_39(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_38(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_40(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_39(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_41(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_40(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_42(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_41(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_43(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_42(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_44(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_43(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_45(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_44(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_46(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_45(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_47(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_46(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_48(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_47(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_49(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_48(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_50(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_49(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_51(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_50(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_52(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_51(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_53(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_52(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_54(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_53(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_55(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_54(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_56(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_55(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_57(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_56(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_58(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_57(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_59(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_58(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_60(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_59(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_61(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_60(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_62(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_61(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_63(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_62(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_64(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_63(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_65(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_64(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_66(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_65(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_67(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_66(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_68(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_67(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_69(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_68(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_70(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_69(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_71(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_70(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_72(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_71(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_73(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_72(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_74(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_73(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_75(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_74(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_76(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_75(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_77(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_76(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_78(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_77(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_79(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_78(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_80(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_79(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_81(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_80(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_82(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_81(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_83(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_82(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_84(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_83(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_85(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_84(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_86(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_85(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_87(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_86(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_88(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_87(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_89(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_88(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_90(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_89(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_91(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_90(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_92(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_91(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_93(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_92(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_94(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_93(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_95(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_94(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_96(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_95(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_97(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_96(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_98(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_97(ACT, ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_99(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_98(ACT, ARG, __VA_ARGS__)
|
||||
|
||||
|
||||
// two para every time. for alias
|
||||
#define X_PACK_L2_2_DEF(ACT, ARG, M, NAME) ACT(ARG, M, NAME)
|
||||
#define X_PACK_L2_2_2(ACT, ARG, M, NAME) X_PACK_L2_2_DEF(ACT, ARG, M, NAME)
|
||||
#define X_PACK_L2_2_4(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_2(ACT,ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_2_6(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_4(ACT,ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_2_8(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_6(ACT,ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_2_10(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_8(ACT,ARG, __VA_ARGS__)
|
||||
#define X_PACK_L2_2_12(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_10(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_14(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_12(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_16(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_14(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_18(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_16(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_20(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_18(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_22(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_20(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_24(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_22(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_26(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_24(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_28(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_26(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_30(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_28(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_32(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_30(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_34(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_32(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_36(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_34(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_38(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_36(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_40(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_38(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_42(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_40(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_44(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_42(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_46(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_44(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_48(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_46(ACT, ARG,__VA_ARGS__)
|
||||
#define X_PACK_L2_2_50(ACT, ARG,M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_48(ACT, ARG,__VA_ARGS__)
|
||||
|
||||
#else // msvc
|
||||
// thx https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
|
||||
// in MSVC's preprocessor, __VA_ARGS__ is treat as a normal parameter, so it will expand at last, and in gcc, it's expand at first. so we need expand it first
|
||||
#define X_PACK_N(LEVEL, ACTION, ...) X_PACK_EXPAND(X_PACK_COUNT(LEVEL, ACTION, __VA_ARGS__,_99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)) X_PACK_EXPAND((ACTION, __VA_ARGS__))
|
||||
|
||||
#define X_PACK_N2(LEVEL, ACTION, ARG, ...) X_PACK_EXPAND(X_PACK_COUNT(LEVEL, ACTION, __VA_ARGS__,_99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1)) X_PACK_EXPAND((ACTION, ARG, __VA_ARGS__))
|
||||
|
||||
#define X_PACK_L1_DEF(ACT, M) ACT(M) // here will expand to ACT(O(xxx)), ACT(A(a,x)), ACT(M(xxx))
|
||||
#define X_PACK_L1_1(ACT, M) X_PACK_L1_DEF(ACT, M)
|
||||
#define X_PACK_L1_2(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_1 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_3(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_2 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_4(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_3 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_5(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_4 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_6(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_5 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_7(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_6 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_8(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_7 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_9(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_8 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_10(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_9 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_11(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_10 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_12(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_11 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_13(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_12 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_14(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_13 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_15(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_14 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_16(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_15 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_17(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_16 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_18(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_17 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_19(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_18 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_20(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_19 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_21(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_20 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_22(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_21 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_23(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_22 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_24(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_23 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_25(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_24 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_26(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_25 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_27(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_26 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_28(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_27 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_29(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_28 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_30(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_29 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_31(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_30 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_32(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_31 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_33(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_32 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_34(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_33 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_35(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_34 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_36(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_35 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_37(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_36 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_38(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_37 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_39(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_38 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_40(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_39 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_41(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_40 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_42(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_41 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_43(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_42 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_44(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_43 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_45(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_44 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_46(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_45 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_47(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_46 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_48(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_47 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_49(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_48 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_50(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_49 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_51(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_50 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_52(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_51 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_53(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_52 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_54(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_53 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_55(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_54 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_56(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_55 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_57(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_56 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_58(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_57 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_59(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_58 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_60(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_59 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_61(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_60 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_62(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_61 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_63(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_62 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_64(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_63 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_65(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_64 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_66(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_65 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_67(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_66 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_68(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_67 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_69(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_68 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_70(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_69 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_71(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_70 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_72(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_71 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_73(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_72 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_74(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_73 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_75(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_74 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_76(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_75 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_77(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_76 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_78(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_77 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_79(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_78 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_80(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_79 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_81(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_80 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_82(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_81 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_83(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_82 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_84(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_83 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_85(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_84 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_86(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_85 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_87(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_86 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_88(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_87 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_89(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_88 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_90(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_89 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_91(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_90 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_92(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_91 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_93(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_92 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_94(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_93 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_95(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_94 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_96(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_95 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_97(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_96 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_98(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_97 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
#define X_PACK_L1_99(ACT, M,...) X_PACK_L1_DEF(ACT, M) X_PACK_L1_98 X_PACK_EXPAND((ACT, __VA_ARGS__))
|
||||
|
||||
#define X_PACK_L2_DEF(ACT, ARG, M) ACT(ARG, M)
|
||||
#define X_PACK_L2_1(ACT, ARG, M) X_PACK_L2_DEF(ACT, ARG, M)
|
||||
#define X_PACK_L2_2(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_1 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_3(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_2 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_4(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_3 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_5(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_4 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_6(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_5 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_7(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_6 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_8(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_7 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_9(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_8 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_10(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_9 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_11(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_10 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_12(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_11 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_13(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_12 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_14(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_13 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_15(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_14 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_16(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_15 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_17(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_16 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_18(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_17 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_19(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_18 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_20(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_19 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_21(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_20 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_22(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_21 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_23(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_22 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_24(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_23 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_25(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_24 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_26(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_25 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_27(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_26 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_28(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_27 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_29(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_28 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_30(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_29 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_31(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_30 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_32(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_31 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_33(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_32 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_34(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_33 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_35(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_34 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_36(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_35 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_37(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_36 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_38(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_37 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_39(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_38 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_40(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_39 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_41(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_40 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_42(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_41 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_43(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_42 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_44(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_43 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_45(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_44 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_46(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_45 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_47(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_46 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_48(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_47 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_49(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_48 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_50(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_49 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_51(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_50 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_52(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_51 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_53(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_52 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_54(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_53 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_55(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_54 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_56(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_55 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_57(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_56 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_58(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_57 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_59(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_58 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_60(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_59 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_61(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_60 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_62(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_61 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_63(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_62 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_64(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_63 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_65(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_64 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_66(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_65 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_67(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_66 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_68(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_67 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_69(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_68 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_70(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_69 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_71(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_70 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_72(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_71 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_73(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_72 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_74(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_73 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_75(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_74 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_76(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_75 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_77(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_76 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_78(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_77 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_79(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_78 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_80(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_79 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_81(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_80 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_82(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_81 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_83(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_82 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_84(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_83 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_85(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_84 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_86(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_85 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_87(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_86 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_88(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_87 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_89(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_88 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_90(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_89 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_91(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_90 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_92(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_91 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_93(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_92 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_94(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_93 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_95(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_94 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_96(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_95 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_97(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_96 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_98(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_97 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_99(ACT, ARG, M,...) X_PACK_L2_DEF(ACT, ARG, M) X_PACK_L2_98 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
|
||||
// two para every time. for alias
|
||||
#define X_PACK_L2_2_DEF(ACT, ARG, M, NAME) ACT(ARG, M, NAME)
|
||||
#define X_PACK_L2_2_2(ACT, ARG, M, NAME) X_PACK_L2_2_DEF(ACT, ARG, M, NAME)
|
||||
#define X_PACK_L2_2_4(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_2 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_6(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_4 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_8(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_6 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_10(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_8 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_12(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_10 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_14(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_12 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_16(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_14 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_18(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_16 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_20(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_18 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_22(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_20 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_24(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_22 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_26(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_24 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_28(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_26 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_30(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_28 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_32(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_30 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_34(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_32 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_36(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_34 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_38(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_36 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_40(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_38 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_42(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_40 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_44(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_42 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_46(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_44 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_48(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_46 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
#define X_PACK_L2_2_50(ACT, ARG, M, NAME,...) X_PACK_L2_2_DEF(ACT, ARG, M, NAME) X_PACK_L2_2_48 X_PACK_EXPAND((ACT, ARG, __VA_ARGS__))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
44
util/xpack/mysql.h
Executable file
44
util/xpack/mysql.h
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_MYSQL_H
|
||||
#define __X_PACK_MYSQL_H
|
||||
|
||||
#include "mysql_decoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class mysql {
|
||||
public:
|
||||
// convert MYSQL_RES to a struct or vector<struct>
|
||||
template <class T>
|
||||
static void decode(MYSQL_RES *result, T &val) {
|
||||
MySQLDecoder de(result);
|
||||
de.decode_top(val, NULL);
|
||||
}
|
||||
|
||||
// select name from test where id = 1; // just want to get name, did not want to use a struct
|
||||
template <class T>
|
||||
static void decode(MYSQL_RES *result, const std::string&field, T &val) {
|
||||
MySQLDecoder de(result);
|
||||
de.decode_column(field.c_str(), val, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
222
util/xpack/mysql_decoder.h
Executable file
222
util/xpack/mysql_decoder.h
Executable file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_MYSQL_DECODER_H
|
||||
#define __X_PACK_MYSQL_DECODER_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#include "extend.h"
|
||||
#include "traits.h"
|
||||
#include "json.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "time.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
// for mysql types not list here
|
||||
// if true we will call xpack_mysql_decode(MYSQL_FIELD *field, char *column, T&val, const Extend *ext)
|
||||
template <class T>
|
||||
struct is_xpack_mysql_xtype {static bool const value = false;};
|
||||
|
||||
class MySQLDecoder {
|
||||
friend class mysql;
|
||||
public:
|
||||
template <typename T>
|
||||
bool decode(const char*key, T&val, const Extend *ext) {
|
||||
int idx = find(key);
|
||||
if (idx >= 0) {
|
||||
return this->decode_type(idx, val, ext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const char *Name() const {
|
||||
return "db";
|
||||
}
|
||||
|
||||
private:
|
||||
MYSQL_RES *_res;
|
||||
MYSQL_ROW _row;
|
||||
std::map<const char*, int, cmp_str> _index;
|
||||
|
||||
MySQLDecoder(MYSQL_RES *result):_res(result), _row(NULL) {
|
||||
mysql_data_seek(_res, 0); // reset cursor to head
|
||||
for (int i=0; i<int(result->field_count); ++i) {
|
||||
_index[result->fields[i].name] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// decode to struct
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_top(T& val, const Extend *ext) {
|
||||
if (NULL != (_row = mysql_fetch_row(_res))) {
|
||||
val.__x_pack_decode(*this, val, ext);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_top(std::vector<T>& val, const Extend *ext) {
|
||||
while (NULL != (_row = mysql_fetch_row(_res))) {
|
||||
val.push_back(T());
|
||||
T& tmp = val.back();
|
||||
tmp.__x_pack_decode(*this, tmp, ext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_top(T& val, const Extend *ext) {
|
||||
if (NULL != (_row = mysql_fetch_row(_res))) {
|
||||
__x_pack_decode_out(*this, val, ext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_top(std::vector<T>& val, const Extend *ext) {
|
||||
while (NULL != (_row = mysql_fetch_row(_res))) {
|
||||
val.push_back(T());
|
||||
__x_pack_decode_out(*this, val.back(), ext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// decode special column of first row
|
||||
template <class T>
|
||||
bool decode_column(const char*field, T&val, const Extend *ext) {
|
||||
int idx;
|
||||
if (NULL==_row && NULL == (_row = mysql_fetch_row(_res)) && (0 > (idx = find(field)))) {
|
||||
return false;
|
||||
}
|
||||
return decode_type(idx, val, ext);
|
||||
}
|
||||
// decode special column of rows
|
||||
template <class T>
|
||||
bool decode_column(const char*field, std::vector<T>&val, const Extend *ext) {
|
||||
int idx;
|
||||
if (0 > (idx = find(field))) {
|
||||
return false;
|
||||
}
|
||||
while (NULL != (_row = mysql_fetch_row(_res))) {
|
||||
T t;
|
||||
decode_type(idx, t, ext);
|
||||
val.push_back(t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int find(const char*field) const {
|
||||
std::map<const char*, int, cmp_str>::const_iterator it = _index.find(field);
|
||||
if (it != _index.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// std::string
|
||||
bool decode_type(const int idx, std::string &val, const Extend *ext) {
|
||||
val = _row[idx];
|
||||
return true;
|
||||
}
|
||||
// bool
|
||||
bool decode_type(const int idx, bool &val, const Extend *ext) {
|
||||
int tmp;
|
||||
if (decode_type(idx, tmp, ext)) {
|
||||
val = tmp != 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// unsigned integer. DATE and TIME use signed plz
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer && !numeric<T>::is_signed, bool>::type decode_type(const int idx, T &val, const Extend *ext) {
|
||||
val = (T)std::strtoul(_row[idx], NULL, 10);
|
||||
return true;
|
||||
}
|
||||
// signed integer
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer && numeric<T>::is_signed, bool>::type decode_type(const int idx, T &val, const Extend *ext) {
|
||||
const char *str = _row[idx];
|
||||
if (str==NULL || str[0]=='\0') {
|
||||
val = 0;
|
||||
return true;
|
||||
}
|
||||
switch (_res->fields[idx].type) {
|
||||
case MYSQL_TYPE_TIME: {
|
||||
std::vector<std::string> ss;
|
||||
if (3 == Util::split(ss, str, ':')) {
|
||||
long int s0 = std::strtol(ss[0].c_str(), NULL, 10);
|
||||
long int s1 = std::strtol(ss[1].c_str(), NULL, 10);
|
||||
long int s2 = std::strtol(ss[2].c_str(), NULL, 10);
|
||||
if (s0 >= 0) {
|
||||
val = 1;
|
||||
} else {
|
||||
val = -1;
|
||||
s0 *= -1;
|
||||
}
|
||||
val *= (T)(s0*3600 + s1*60 +s2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_TIMESTAMP:{ // parse to unix timestamp, seconds, discard fractional part
|
||||
tm t;
|
||||
strptime(str, "%F %T", &t);
|
||||
val = (T)mktime(&t);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = (T)std::strtol(str, NULL, 10);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// float
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type decode_type(const int idx, T &val, const Extend *ext) {
|
||||
val = (T)std::strtod(_row[idx], NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
// mysql covert type
|
||||
template <class T>
|
||||
inline typename x_enable_if<is_xpack_mysql_xtype<T>::value, bool>::type decode_type(const int idx, T &val, const Extend *ext) {
|
||||
return xpack_mysql_decode(&_res->fields[idx], _row[idx], val, ext);
|
||||
}
|
||||
|
||||
// class/struct defined XPACK/XPACK_OUT, default use json to parse, if use other, use xpack_mysql_decode
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_type(const int idx, T &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return xpack::json::decode(_row[idx], val);
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_type(const int idx, T &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
return xpack::json::decode(_row[idx], val);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
69
util/xpack/numeric.h
Executable file
69
util/xpack/numeric.h
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_NUMERIC_H
|
||||
#define __X_PACK_NUMERIC_H
|
||||
|
||||
namespace xpack {
|
||||
|
||||
template <class T>
|
||||
struct numeric{static bool const value = false; static bool const is_integer = false;static bool const is_float = false;static bool const is_signed = false;};
|
||||
|
||||
template<>
|
||||
struct numeric<char>{static bool const value = true; static bool const is_integer = true;static bool const is_signed = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<signed char>{static bool const value = true; static bool const is_integer = true;static bool const is_signed = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<unsigned char>{static bool const value = true; static bool const is_integer = true;;static bool const is_signed = false;};
|
||||
|
||||
template<>
|
||||
struct numeric<short>{static bool const value = true; static bool const is_integer = true;static bool const is_signed = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<unsigned short>{static bool const value = true; static bool const is_integer = true;;static bool const is_signed = false;};
|
||||
|
||||
template<>
|
||||
struct numeric<int>{static bool const value = true; static bool const is_integer = true;static bool const is_signed = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<unsigned int>{static bool const value = true; static bool const is_integer = true;;static bool const is_signed = false;};
|
||||
|
||||
template<>
|
||||
struct numeric<long>{static bool const value = true; static bool const is_integer = true;static bool const is_signed = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<unsigned long>{static bool const value = true; static bool const is_integer = true;;static bool const is_signed = false;};
|
||||
|
||||
template<>
|
||||
struct numeric<long long>{static bool const value = true; static bool const is_integer = true;static bool const is_signed = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<unsigned long long>{static bool const value = true; static bool const is_integer = true;;static bool const is_signed = false;};
|
||||
|
||||
template<>
|
||||
struct numeric<float>{static bool const value = true;static bool const is_float = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<double>{static bool const value = true;static bool const is_float = true;};
|
||||
|
||||
template<>
|
||||
struct numeric<long double>{static bool const value = true;static bool const is_float = true;};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
284
util/xpack/rapidjson/allocators.h
Executable file
284
util/xpack/rapidjson/allocators.h
Executable file
|
|
@ -0,0 +1,284 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
|
||||
/*! \def RAPIDJSON_ALLOCATOR_DEFUALT_CHUNK_CAPACITY
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief User-defined kDefaultChunkCapacity definition.
|
||||
|
||||
User can define this as any \c size that is a power of 2.
|
||||
*/
|
||||
|
||||
#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
|
||||
#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) {
|
||||
if (size) // behavior of malloc(0) is implementation defined.
|
||||
return std::malloc(size);
|
||||
else
|
||||
return NULL; // standardize to returning NULL.
|
||||
}
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
(void)originalSize;
|
||||
if (newSize == 0) {
|
||||
std::free(originalPtr);
|
||||
return NULL;
|
||||
}
|
||||
return std::realloc(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { std::free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
|
||||
return NULL;
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
originalSize = RAPIDJSON_ALIGN(originalSize);
|
||||
newSize = RAPIDJSON_ALIGN(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
if (void* newBuffer = Malloc(newSize)) {
|
||||
if (originalSize)
|
||||
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||
return newBuffer;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
\return true if success.
|
||||
*/
|
||||
bool AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
|
||||
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
78
util/xpack/rapidjson/cursorstreamwrapper.h
Executable file
78
util/xpack/rapidjson/cursorstreamwrapper.h
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
|
||||
#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#if defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
//! Cursor stream wrapper for counting line and column number if error exists.
|
||||
/*!
|
||||
\tparam InputStream Any stream that implements Stream Concept
|
||||
*/
|
||||
template <typename InputStream, typename Encoding = UTF8<> >
|
||||
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
CursorStreamWrapper(InputStream& is):
|
||||
GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
|
||||
|
||||
// counting line and column number
|
||||
Ch Take() {
|
||||
Ch ch = this->is_.Take();
|
||||
if(ch == '\n') {
|
||||
line_ ++;
|
||||
col_ = 0;
|
||||
} else {
|
||||
col_ ++;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
//! Get the error line number, if error exists.
|
||||
size_t GetLine() const { return line_; }
|
||||
//! Get the error column number, if error exists.
|
||||
size_t GetColumn() const { return col_; }
|
||||
|
||||
private:
|
||||
size_t line_; //!< Current Line
|
||||
size_t col_; //!< Current Column
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
|
||||
2652
util/xpack/rapidjson/document.h
Executable file
2652
util/xpack/rapidjson/document.h
Executable file
File diff suppressed because it is too large
Load diff
299
util/xpack/rapidjson/encodedstream.h
Executable file
299
util/xpack/rapidjson/encodedstream.h
Executable file
|
|
@ -0,0 +1,299 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "memorystream.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Input byte stream wrapper with a statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||
*/
|
||||
template <typename Encoding, typename InputByteStream>
|
||||
class EncodedInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||
current_ = Encoding::TakeBOM(is_);
|
||||
}
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
|
||||
InputByteStream& is_;
|
||||
Ch current_;
|
||||
};
|
||||
|
||||
//! Specialized for UTF8 MemoryStream.
|
||||
template <>
|
||||
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||
public:
|
||||
typedef UTF8<>::Ch Ch;
|
||||
|
||||
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||
}
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) {}
|
||||
void Flush() {}
|
||||
Ch* PutBegin() { return 0; }
|
||||
size_t PutEnd(Ch*) { return 0; }
|
||||
|
||||
MemoryStream& is_;
|
||||
|
||||
private:
|
||||
EncodedInputStream(const EncodedInputStream&);
|
||||
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||
if (putBOM)
|
||||
Encoding::PutBOM(os_);
|
||||
}
|
||||
|
||||
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||
void Flush() { os_.Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
EncodedOutputStream(const EncodedOutputStream&);
|
||||
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||
|
||||
OutputByteStream& os_;
|
||||
};
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for reading.
|
||||
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename InputByteStream>
|
||||
class AutoUTFInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
}
|
||||
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
InputByteStream* is_;
|
||||
UTFType type_;
|
||||
Ch current_;
|
||||
TakeFunc takeFunc_;
|
||||
bool hasBOM_;
|
||||
};
|
||||
|
||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam OutputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
716
util/xpack/rapidjson/encodings.h
Executable file
716
util/xpack/rapidjson/encodings.h
Executable file
|
|
@ -0,0 +1,716 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ENCODINGS_H_
|
||||
#define RAPIDJSON_ENCODINGS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#elif defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
RAPIDJSON_DIAG_OFF(overflow)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encoding
|
||||
|
||||
/*! \class rapidjson::Encoding
|
||||
\brief Concept for encoding of Unicode characters.
|
||||
|
||||
\code
|
||||
concept Encoding {
|
||||
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||
|
||||
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||
|
||||
//! \brief Encode a Unicode codepoint to an output stream.
|
||||
//! \param os Output stream.
|
||||
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint);
|
||||
|
||||
//! \brief Decode a Unicode codepoint from an input stream.
|
||||
//! \param is Input stream.
|
||||
//! \param codepoint Output of the unicode codepoint.
|
||||
//! \return true if a valid codepoint can be decoded from the stream.
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||
|
||||
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||
//! \param is Input stream to obtain codepoint.
|
||||
//! \param os Output for copying one codepoint.
|
||||
//! \return true if it is valid.
|
||||
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os);
|
||||
|
||||
// The following functions are deal with byte streams.
|
||||
|
||||
//! Take a character from input byte stream, skip BOM if exist.
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is);
|
||||
|
||||
//! Take a character from input byte stream.
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is);
|
||||
|
||||
//! Put BOM to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os);
|
||||
|
||||
//! Put a character to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF8
|
||||
|
||||
//! UTF-8 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||
http://tools.ietf.org/html/rfc3629
|
||||
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (!(c & 0x80)) {
|
||||
*codepoint = static_cast<unsigned char>(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||
if (type >= 32) {
|
||||
*codepoint = 0;
|
||||
} else {
|
||||
*codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
|
||||
}
|
||||
bool result = true;
|
||||
switch (type) {
|
||||
case 2: RAPIDJSON_TAIL(); return result;
|
||||
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
|
||||
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
|
||||
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef RAPIDJSON_COPY
|
||||
#undef RAPIDJSON_TRANS
|
||||
#undef RAPIDJSON_TAIL
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
#define RAPIDJSON_COPY() os.Put(c = is.Take())
|
||||
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
|
||||
Ch c;
|
||||
RAPIDJSON_COPY();
|
||||
if (!(c & 0x80))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||
case 2: RAPIDJSON_TAIL(); return result;
|
||||
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
|
||||
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
|
||||
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
|
||||
default: return false;
|
||||
}
|
||||
#undef RAPIDJSON_COPY
|
||||
#undef RAPIDJSON_TRANS
|
||||
#undef RAPIDJSON_TAIL
|
||||
}
|
||||
|
||||
static unsigned char GetRange(unsigned char c) {
|
||||
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||
static const unsigned char type[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
};
|
||||
return type[c];
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
typename InputByteStream::Ch c = Take(is);
|
||||
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||
c = is.Take();
|
||||
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||
c = is.Take();
|
||||
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||
c = is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF16
|
||||
|
||||
//! UTF-16 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||
http://tools.ietf.org/html/rfc2781
|
||||
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
if (codepoint <= 0xFFFF) {
|
||||
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
typename InputStream::Ch c = is.Take();
|
||||
if (c < 0xD800 || c > 0xDFFF) {
|
||||
*codepoint = static_cast<unsigned>(c);
|
||||
return true;
|
||||
}
|
||||
else if (c <= 0xDBFF) {
|
||||
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||
c = is.Take();
|
||||
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||
*codepoint += 0x10000;
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
typename InputStream::Ch c;
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||
if (c < 0xD800 || c > 0xDFFF)
|
||||
return true;
|
||||
else if (c <= 0xDBFF) {
|
||||
os.Put(c = is.Take());
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 little endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16LE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 big endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16BE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// UTF32
|
||||
|
||||
//! UTF-32 encoding.
|
||||
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||
\note implements Encoding concept
|
||||
|
||||
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||
*/
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(codepoint);
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
PutUnsafe(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c = is.Take();
|
||||
*codepoint = c;
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||
Ch c;
|
||||
os.Put(c = is.Take());
|
||||
return c <= 0x10FFFF;
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 little endian enocoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32LE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<uint8_t>(is.Take());
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 big endian encoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32BE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||
return static_cast<CharType>(c);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ASCII
|
||||
|
||||
//! ASCII encoding.
|
||||
/*! http://en.wikipedia.org/wiki/ASCII
|
||||
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||
\note implements Encoding concept
|
||||
*/
|
||||
template<typename CharType = char>
|
||||
struct ASCII {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 0 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
*codepoint = c;
|
||||
return c <= 0X7F;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||
return c <= 0x7F;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||
return static_cast<Ch>(c);
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return static_cast<Ch>(is.Take());
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
(void)os;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AutoUTF
|
||||
|
||||
//! Runtime-specified UTF encoding type of a stream.
|
||||
enum UTFType {
|
||||
kUTF8 = 0, //!< UTF-8.
|
||||
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||
};
|
||||
|
||||
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||
*/
|
||||
template<typename CharType>
|
||||
struct AutoUTF {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
template<typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template<typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
|
||||
(*f[os.GetType()])(os, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||
return (*f[is.GetType()])(is, codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
|
||||
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||
return (*f[is.GetType()])(is, os);
|
||||
}
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Transcoder
|
||||
|
||||
//! Encoding conversion.
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder {
|
||||
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::Encode(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::EncodeUnsafe(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Validate one Unicode codepoint from an encoded stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||
}
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
template<typename Stream>
|
||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
|
||||
|
||||
//! Specialization of Transcoder with same source and target encoding.
|
||||
template<typename Encoding>
|
||||
struct Transcoder<Encoding, Encoding> {
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
|
||||
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename InputStream, typename OutputStream>
|
||||
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||
}
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
74
util/xpack/rapidjson/error/en.h
Executable file
74
util/xpack/rapidjson/error/en.h
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||
#define RAPIDJSON_ERROR_EN_H_
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_ERRORS
|
||||
\param parseErrorCode Error code obtained in parsing.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||
switch (parseErrorCode) {
|
||||
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
|
||||
|
||||
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||
|
||||
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||
|
||||
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||
|
||||
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||
|
||||
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||
|
||||
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
|
||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ERROR_EN_H_
|
||||
161
util/xpack/rapidjson/error/error.h
Executable file
161
util/xpack/rapidjson/error/error.h
Executable file
|
|
@ -0,0 +1,161 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||
#define RAPIDJSON_ERROR_ERROR_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
/*! \file error.h */
|
||||
|
||||
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_CHARTYPE
|
||||
|
||||
//! Character type of error messages.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
The default character type is \c char.
|
||||
On Windows, user can define this macro as \c TCHAR for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_STRING
|
||||
|
||||
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
By default this conversion macro does nothing.
|
||||
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_STRING
|
||||
#define RAPIDJSON_ERROR_STRING(x) x
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseErrorCode
|
||||
|
||||
//! Error code of parsing.
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
\see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||
*/
|
||||
enum ParseErrorCode {
|
||||
kParseErrorNone = 0, //!< No error.
|
||||
|
||||
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||
|
||||
kParseErrorValueInvalid, //!< Invalid value.
|
||||
|
||||
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||
|
||||
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||
|
||||
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||
|
||||
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||
|
||||
kParseErrorTermination, //!< Parsing was terminated.
|
||||
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
|
||||
};
|
||||
|
||||
//! Result of parsing (wraps ParseErrorCode)
|
||||
/*!
|
||||
\ingroup RAPIDJSON_ERRORS
|
||||
\code
|
||||
Document doc;
|
||||
ParseResult ok = doc.Parse("[42]");
|
||||
if (!ok) {
|
||||
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||
GetParseError_En(ok.Code()), ok.Offset());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
\endcode
|
||||
\see GenericReader::Parse, GenericDocument::Parse
|
||||
*/
|
||||
struct ParseResult {
|
||||
//!! Unspecified boolean type
|
||||
typedef bool (ParseResult::*BooleanType)() const;
|
||||
public:
|
||||
//! Default constructor, no error.
|
||||
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||
//! Constructor to set an error.
|
||||
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||
|
||||
//! Get the error code.
|
||||
ParseErrorCode Code() const { return code_; }
|
||||
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||
size_t Offset() const { return offset_; }
|
||||
|
||||
//! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||
operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
|
||||
//! Whether the result is an error.
|
||||
bool IsError() const { return code_ != kParseErrorNone; }
|
||||
|
||||
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||
|
||||
bool operator!=(const ParseResult& that) const { return !(*this == that); }
|
||||
bool operator!=(ParseErrorCode code) const { return !(*this == code); }
|
||||
friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
|
||||
|
||||
//! Reset error code.
|
||||
void Clear() { Set(kParseErrorNone); }
|
||||
//! Update error code and offset.
|
||||
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||
|
||||
private:
|
||||
ParseErrorCode code_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
||||
//! Function pointer type of GetParseError().
|
||||
/*! \ingroup RAPIDJSON_ERRORS
|
||||
|
||||
This is the prototype for \c GetParseError_X(), where \c X is a locale.
|
||||
User can dynamically change locale in runtime, e.g.:
|
||||
\code
|
||||
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||
\endcode
|
||||
*/
|
||||
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ERROR_ERROR_H_
|
||||
99
util/xpack/rapidjson/filereadstream.h
Executable file
99
util/xpack/rapidjson/filereadstream.h
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileReadStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type (byte).
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param fp File pointer opened for read.
|
||||
\param buffer user-supplied buffer.
|
||||
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||
*/
|
||||
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||
Read();
|
||||
}
|
||||
|
||||
Ch Peek() const { return *current_; }
|
||||
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void Read() {
|
||||
if (current_ < bufferLast_)
|
||||
++current_;
|
||||
else if (!eof_) {
|
||||
count_ += readCount_;
|
||||
readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (readCount_ < bufferSize_) {
|
||||
buffer_[readCount_] = '\0';
|
||||
++bufferLast_;
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
104
util/xpack/rapidjson/filewritestream.h
Executable file
104
util/xpack/rapidjson/filewritestream.h
Executable file
|
|
@ -0,0 +1,104 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of C file stream for output using fwrite().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
std::memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
std::memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
}
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
std::FILE* fp_;
|
||||
char *buffer_;
|
||||
char *bufferEnd_;
|
||||
char *current_;
|
||||
};
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
151
util/xpack/rapidjson/fwd.h
Executable file
151
util/xpack/rapidjson/fwd.h
Executable file
|
|
@ -0,0 +1,151 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FWD_H_
|
||||
#define RAPIDJSON_FWD_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
// encodings.h
|
||||
|
||||
template<typename CharType> struct UTF8;
|
||||
template<typename CharType> struct UTF16;
|
||||
template<typename CharType> struct UTF16BE;
|
||||
template<typename CharType> struct UTF16LE;
|
||||
template<typename CharType> struct UTF32;
|
||||
template<typename CharType> struct UTF32BE;
|
||||
template<typename CharType> struct UTF32LE;
|
||||
template<typename CharType> struct ASCII;
|
||||
template<typename CharType> struct AutoUTF;
|
||||
|
||||
template<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder;
|
||||
|
||||
// allocators.h
|
||||
|
||||
class CrtAllocator;
|
||||
|
||||
template <typename BaseAllocator>
|
||||
class MemoryPoolAllocator;
|
||||
|
||||
// stream.h
|
||||
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream;
|
||||
|
||||
typedef GenericStringStream<UTF8<char> > StringStream;
|
||||
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream;
|
||||
|
||||
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
|
||||
|
||||
// stringbuffer.h
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericStringBuffer;
|
||||
|
||||
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
|
||||
|
||||
// filereadstream.h
|
||||
|
||||
class FileReadStream;
|
||||
|
||||
// filewritestream.h
|
||||
|
||||
class FileWriteStream;
|
||||
|
||||
// memorybuffer.h
|
||||
|
||||
template <typename Allocator>
|
||||
struct GenericMemoryBuffer;
|
||||
|
||||
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
|
||||
|
||||
// memorystream.h
|
||||
|
||||
struct MemoryStream;
|
||||
|
||||
// reader.h
|
||||
|
||||
template<typename Encoding, typename Derived>
|
||||
struct BaseReaderHandler;
|
||||
|
||||
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
|
||||
class GenericReader;
|
||||
|
||||
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
|
||||
|
||||
// writer.h
|
||||
|
||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||
class Writer;
|
||||
|
||||
// prettywriter.h
|
||||
|
||||
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||
class PrettyWriter;
|
||||
|
||||
// document.h
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
struct GenericMember;
|
||||
|
||||
template <bool Const, typename Encoding, typename Allocator>
|
||||
class GenericMemberIterator;
|
||||
|
||||
template<typename CharType>
|
||||
struct GenericStringRef;
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericValue;
|
||||
|
||||
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
|
||||
|
||||
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||
class GenericDocument;
|
||||
|
||||
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
|
||||
|
||||
// pointer.h
|
||||
|
||||
template <typename ValueType, typename Allocator>
|
||||
class GenericPointer;
|
||||
|
||||
typedef GenericPointer<Value, CrtAllocator> Pointer;
|
||||
|
||||
// schema.h
|
||||
|
||||
template <typename SchemaDocumentType>
|
||||
class IGenericRemoteSchemaDocumentProvider;
|
||||
|
||||
template <typename ValueT, typename Allocator>
|
||||
class GenericSchemaDocument;
|
||||
|
||||
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
|
||||
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
|
||||
|
||||
template <
|
||||
typename SchemaDocumentType,
|
||||
typename OutputHandler,
|
||||
typename StateAllocator>
|
||||
class GenericSchemaValidator;
|
||||
|
||||
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSONFWD_H_
|
||||
290
util/xpack/rapidjson/internal/biginteger.h
Executable file
290
util/xpack/rapidjson/internal/biginteger.h
Executable file
|
|
@ -0,0 +1,290 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_BIGINTEGER_H_
|
||||
#define RAPIDJSON_BIGINTEGER_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
|
||||
#include <intrin.h> // for _umul128
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
class BigInteger {
|
||||
public:
|
||||
typedef uint64_t Type;
|
||||
|
||||
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
|
||||
explicit BigInteger(uint64_t u) : count_(1) {
|
||||
digits_[0] = u;
|
||||
}
|
||||
|
||||
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||
RAPIDJSON_ASSERT(length > 0);
|
||||
digits_[0] = 0;
|
||||
size_t i = 0;
|
||||
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
|
||||
while (length >= kMaxDigitPerIteration) {
|
||||
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
|
||||
length -= kMaxDigitPerIteration;
|
||||
i += kMaxDigitPerIteration;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
AppendDecimal64(decimals + i, decimals + i + length);
|
||||
}
|
||||
|
||||
BigInteger& operator=(const BigInteger &rhs)
|
||||
{
|
||||
if (this != &rhs) {
|
||||
count_ = rhs.count_;
|
||||
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator=(uint64_t u) {
|
||||
digits_[0] = u;
|
||||
count_ = 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator+=(uint64_t u) {
|
||||
Type backup = digits_[0];
|
||||
digits_[0] += u;
|
||||
for (size_t i = 0; i < count_ - 1; i++) {
|
||||
if (digits_[i] >= backup)
|
||||
return *this; // no carry
|
||||
backup = digits_[i + 1];
|
||||
digits_[i + 1] += 1;
|
||||
}
|
||||
|
||||
// Last carry
|
||||
if (digits_[count_ - 1] < backup)
|
||||
PushBack(1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator*=(uint64_t u) {
|
||||
if (u == 0) return *this = 0;
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
uint64_t hi;
|
||||
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
|
||||
k = hi;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
PushBack(k);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator*=(uint32_t u) {
|
||||
if (u == 0) return *this = 0;
|
||||
if (u == 1) return *this;
|
||||
if (*this == 1) return *this = u;
|
||||
|
||||
uint64_t k = 0;
|
||||
for (size_t i = 0; i < count_; i++) {
|
||||
const uint64_t c = digits_[i] >> 32;
|
||||
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||
const uint64_t uc = u * c;
|
||||
const uint64_t ud = u * d;
|
||||
const uint64_t p0 = ud + k;
|
||||
const uint64_t p1 = uc + (p0 >> 32);
|
||||
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
|
||||
k = p1 >> 32;
|
||||
}
|
||||
|
||||
if (k > 0)
|
||||
PushBack(k);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigInteger& operator<<=(size_t shift) {
|
||||
if (IsZero() || shift == 0) return *this;
|
||||
|
||||
size_t offset = shift / kTypeBit;
|
||||
size_t interShift = shift % kTypeBit;
|
||||
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||
|
||||
if (interShift == 0) {
|
||||
std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
|
||||
count_ += offset;
|
||||
}
|
||||
else {
|
||||
digits_[count_] = 0;
|
||||
for (size_t i = count_; i > 0; i--)
|
||||
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
|
||||
digits_[offset] = digits_[0] << interShift;
|
||||
count_ += offset;
|
||||
if (digits_[count_])
|
||||
count_++;
|
||||
}
|
||||
|
||||
std::memset(digits_, 0, offset * sizeof(Type));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const BigInteger& rhs) const {
|
||||
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
|
||||
}
|
||||
|
||||
bool operator==(const Type rhs) const {
|
||||
return count_ == 1 && digits_[0] == rhs;
|
||||
}
|
||||
|
||||
BigInteger& MultiplyPow5(unsigned exp) {
|
||||
static const uint32_t kPow5[12] = {
|
||||
5,
|
||||
5 * 5,
|
||||
5 * 5 * 5,
|
||||
5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
|
||||
};
|
||||
if (exp == 0) return *this;
|
||||
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
|
||||
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
|
||||
if (exp > 0) *this *= kPow5[exp - 1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Compute absolute difference of this and rhs.
|
||||
// Assume this != rhs
|
||||
bool Difference(const BigInteger& rhs, BigInteger* out) const {
|
||||
int cmp = Compare(rhs);
|
||||
RAPIDJSON_ASSERT(cmp != 0);
|
||||
const BigInteger *a, *b; // Makes a > b
|
||||
bool ret;
|
||||
if (cmp < 0) { a = &rhs; b = this; ret = true; }
|
||||
else { a = this; b = &rhs; ret = false; }
|
||||
|
||||
Type borrow = 0;
|
||||
for (size_t i = 0; i < a->count_; i++) {
|
||||
Type d = a->digits_[i] - borrow;
|
||||
if (i < b->count_)
|
||||
d -= b->digits_[i];
|
||||
borrow = (d > a->digits_[i]) ? 1 : 0;
|
||||
out->digits_[i] = d;
|
||||
if (d != 0)
|
||||
out->count_ = i + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Compare(const BigInteger& rhs) const {
|
||||
if (count_ != rhs.count_)
|
||||
return count_ < rhs.count_ ? -1 : 1;
|
||||
|
||||
for (size_t i = count_; i-- > 0;)
|
||||
if (digits_[i] != rhs.digits_[i])
|
||||
return digits_[i] < rhs.digits_[i] ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t GetCount() const { return count_; }
|
||||
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
|
||||
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||
|
||||
private:
|
||||
void AppendDecimal64(const char* begin, const char* end) {
|
||||
uint64_t u = ParseUint64(begin, end);
|
||||
if (IsZero())
|
||||
*this = u;
|
||||
else {
|
||||
unsigned exp = static_cast<unsigned>(end - begin);
|
||||
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
|
||||
}
|
||||
}
|
||||
|
||||
void PushBack(Type digit) {
|
||||
RAPIDJSON_ASSERT(count_ < kCapacity);
|
||||
digits_[count_++] = digit;
|
||||
}
|
||||
|
||||
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||
uint64_t r = 0;
|
||||
for (const char* p = begin; p != end; ++p) {
|
||||
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Assume a * b + k < 2^128
|
||||
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t low = _umul128(a, b, outHigh) + k;
|
||||
if (low < k)
|
||||
(*outHigh)++;
|
||||
return low;
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||
p += k;
|
||||
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||
return static_cast<uint64_t>(p);
|
||||
#else
|
||||
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
|
||||
x1 += (x0 >> 32); // can't give carry
|
||||
x1 += x2;
|
||||
if (x1 < x2)
|
||||
x3 += (static_cast<uint64_t>(1) << 32);
|
||||
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
|
||||
uint64_t hi = x3 + (x1 >> 32);
|
||||
|
||||
lo += k;
|
||||
if (lo < k)
|
||||
hi++;
|
||||
*outHigh = hi;
|
||||
return lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
|
||||
static const size_t kCapacity = kBitCount / sizeof(Type);
|
||||
static const size_t kTypeBit = sizeof(Type) * 8;
|
||||
|
||||
Type digits_[kCapacity];
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_BIGINTEGER_H_
|
||||
271
util/xpack/rapidjson/internal/diyfp.h
Executable file
271
util/xpack/rapidjson/internal/diyfp.h
Executable file
|
|
@ -0,0 +1,271 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef RAPIDJSON_DIYFP_H_
|
||||
#define RAPIDJSON_DIYFP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
#include <limits>
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanReverse64)
|
||||
#pragma intrinsic(_umul128)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
struct DiyFp {
|
||||
DiyFp() : f(), e() {}
|
||||
|
||||
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
|
||||
|
||||
explicit DiyFp(double d) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u = { d };
|
||||
|
||||
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||
if (biased_e != 0) {
|
||||
f = significand + kDpHiddenBit;
|
||||
e = biased_e - kDpExponentBias;
|
||||
}
|
||||
else {
|
||||
f = significand;
|
||||
e = kDpMinExponent + 1;
|
||||
}
|
||||
}
|
||||
|
||||
DiyFp operator-(const DiyFp& rhs) const {
|
||||
return DiyFp(f - rhs.f, e);
|
||||
}
|
||||
|
||||
DiyFp operator*(const DiyFp& rhs) const {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t h;
|
||||
uint64_t l = _umul128(f, rhs.f, &h);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
__extension__ typedef unsigned __int128 uint128;
|
||||
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||
uint64_t l = static_cast<uint64_t>(p);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#else
|
||||
const uint64_t M32 = 0xFFFFFFFF;
|
||||
const uint64_t a = f >> 32;
|
||||
const uint64_t b = f & M32;
|
||||
const uint64_t c = rhs.f >> 32;
|
||||
const uint64_t d = rhs.f & M32;
|
||||
const uint64_t ac = a * c;
|
||||
const uint64_t bc = b * c;
|
||||
const uint64_t ad = a * d;
|
||||
const uint64_t bd = b * d;
|
||||
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||
tmp += 1U << 31; /// mult_round
|
||||
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||
#endif
|
||||
}
|
||||
|
||||
DiyFp Normalize() const {
|
||||
RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
unsigned long index;
|
||||
_BitScanReverse64(&index, f);
|
||||
return DiyFp(f << (63 - index), e - (63 - index));
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
int s = __builtin_clzll(f);
|
||||
return DiyFp(f << s, e - s);
|
||||
#else
|
||||
DiyFp res = *this;
|
||||
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
DiyFp NormalizeBoundary() const {
|
||||
DiyFp res = *this;
|
||||
while (!(res.f & (kDpHiddenBit << 1))) {
|
||||
res.f <<= 1;
|
||||
res.e--;
|
||||
}
|
||||
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||
return res;
|
||||
}
|
||||
|
||||
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||
mi.f <<= mi.e - pl.e;
|
||||
mi.e = pl.e;
|
||||
*plus = pl;
|
||||
*minus = mi;
|
||||
}
|
||||
|
||||
double ToDouble() const {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
}u;
|
||||
RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
|
||||
if (e < kDpDenormalExponent) {
|
||||
// Underflow.
|
||||
return 0.0;
|
||||
}
|
||||
if (e >= kDpMaxExponent) {
|
||||
// Overflow.
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||
static_cast<uint64_t>(e + kDpExponentBias);
|
||||
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
static const int kDiySignificandSize = 64;
|
||||
static const int kDpSignificandSize = 52;
|
||||
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||
static const int kDpMinExponent = -kDpExponentBias;
|
||||
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
uint64_t f;
|
||||
int e;
|
||||
};
|
||||
|
||||
inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||
// 10^-348, 10^-340, ..., 10^340
|
||||
static const uint64_t kCachedPowers_F[] = {
|
||||
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||
};
|
||||
static const int16_t kCachedPowers_E[] = {
|
||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||
907, 933, 960, 986, 1013, 1039, 1066
|
||||
};
|
||||
RAPIDJSON_ASSERT(index < 87);
|
||||
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower(int e, int* K) {
|
||||
|
||||
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||
int k = static_cast<int>(dk);
|
||||
if (dk - k > 0.0)
|
||||
k++;
|
||||
|
||||
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||
RAPIDJSON_ASSERT(exp >= -348);
|
||||
unsigned index = static_cast<unsigned>(exp + 348) / 8u;
|
||||
*outExp = -348 + static_cast<int>(index) * 8;
|
||||
return GetCachedPowerByIndex(index);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_DIYFP_H_
|
||||
245
util/xpack/rapidjson/internal/dtoa.h
Executable file
245
util/xpack/rapidjson/internal/dtoa.h
Executable file
|
|
@ -0,0 +1,245 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef RAPIDJSON_DTOA_
|
||||
#define RAPIDJSON_DTOA_
|
||||
|
||||
#include "itoa.h" // GetDigitsLut()
|
||||
#include "diyfp.h"
|
||||
#include "ieee754.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
|
||||
#endif
|
||||
|
||||
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
||||
while (rest < wp_w && delta - rest >= ten_kappa &&
|
||||
(rest + ten_kappa < wp_w || /// closer
|
||||
wp_w - rest > rest + ten_kappa - wp_w)) {
|
||||
buffer[len - 1]--;
|
||||
rest += ten_kappa;
|
||||
}
|
||||
}
|
||||
|
||||
inline int CountDecimalDigit32(uint32_t n) {
|
||||
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||
if (n < 10) return 1;
|
||||
if (n < 100) return 2;
|
||||
if (n < 1000) return 3;
|
||||
if (n < 10000) return 4;
|
||||
if (n < 100000) return 5;
|
||||
if (n < 1000000) return 6;
|
||||
if (n < 10000000) return 7;
|
||||
if (n < 100000000) return 8;
|
||||
// Will not reach 10 digits in DigitGen()
|
||||
//if (n < 1000000000) return 9;
|
||||
//return 10;
|
||||
return 9;
|
||||
}
|
||||
|
||||
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||
const DiyFp wp_w = Mp - W;
|
||||
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||
uint64_t p2 = Mp.f & (one.f - 1);
|
||||
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||
*len = 0;
|
||||
|
||||
while (kappa > 0) {
|
||||
uint32_t d = 0;
|
||||
switch (kappa) {
|
||||
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
||||
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
||||
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
||||
case 6: d = p1 / 100000; p1 %= 100000; break;
|
||||
case 5: d = p1 / 10000; p1 %= 10000; break;
|
||||
case 4: d = p1 / 1000; p1 %= 1000; break;
|
||||
case 3: d = p1 / 100; p1 %= 100; break;
|
||||
case 2: d = p1 / 10; p1 %= 10; break;
|
||||
case 1: d = p1; p1 = 0; break;
|
||||
default:;
|
||||
}
|
||||
if (d || *len)
|
||||
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
|
||||
kappa--;
|
||||
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||
if (tmp <= delta) {
|
||||
*K += kappa;
|
||||
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// kappa = 0
|
||||
for (;;) {
|
||||
p2 *= 10;
|
||||
delta *= 10;
|
||||
char d = static_cast<char>(p2 >> -one.e);
|
||||
if (d || *len)
|
||||
buffer[(*len)++] = static_cast<char>('0' + d);
|
||||
p2 &= one.f - 1;
|
||||
kappa--;
|
||||
if (p2 < delta) {
|
||||
*K += kappa;
|
||||
int index = -kappa;
|
||||
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
||||
const DiyFp v(value);
|
||||
DiyFp w_m, w_p;
|
||||
v.NormalizedBoundaries(&w_m, &w_p);
|
||||
|
||||
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||
const DiyFp W = v.Normalize() * c_mk;
|
||||
DiyFp Wp = w_p * c_mk;
|
||||
DiyFp Wm = w_m * c_mk;
|
||||
Wm.f++;
|
||||
Wp.f--;
|
||||
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||
}
|
||||
|
||||
inline char* WriteExponent(int K, char* buffer) {
|
||||
if (K < 0) {
|
||||
*buffer++ = '-';
|
||||
K = -K;
|
||||
}
|
||||
|
||||
if (K >= 100) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
|
||||
K %= 100;
|
||||
const char* d = GetDigitsLut() + K * 2;
|
||||
*buffer++ = d[0];
|
||||
*buffer++ = d[1];
|
||||
}
|
||||
else if (K >= 10) {
|
||||
const char* d = GetDigitsLut() + K * 2;
|
||||
*buffer++ = d[0];
|
||||
*buffer++ = d[1];
|
||||
}
|
||||
else
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
||||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||
|
||||
if (0 <= k && kk <= 21) {
|
||||
// 1234e7 -> 12340000000
|
||||
for (int i = length; i < kk; i++)
|
||||
buffer[i] = '0';
|
||||
buffer[kk] = '.';
|
||||
buffer[kk + 1] = '0';
|
||||
return &buffer[kk + 2];
|
||||
}
|
||||
else if (0 < kk && kk <= 21) {
|
||||
// 1234e-2 -> 12.34
|
||||
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||
buffer[kk] = '.';
|
||||
if (0 > k + maxDecimalPlaces) {
|
||||
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
||||
// Remove extra trailing zeros (at least one) after truncation.
|
||||
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
||||
if (buffer[i] != '0')
|
||||
return &buffer[i + 1];
|
||||
return &buffer[kk + 2]; // Reserve one zero
|
||||
}
|
||||
else
|
||||
return &buffer[length + 1];
|
||||
}
|
||||
else if (-6 < kk && kk <= 0) {
|
||||
// 1234e-6 -> 0.001234
|
||||
const int offset = 2 - kk;
|
||||
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 2; i < offset; i++)
|
||||
buffer[i] = '0';
|
||||
if (length - kk > maxDecimalPlaces) {
|
||||
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
|
||||
// Remove extra trailing zeros (at least one) after truncation.
|
||||
for (int i = maxDecimalPlaces + 1; i > 2; i--)
|
||||
if (buffer[i] != '0')
|
||||
return &buffer[i + 1];
|
||||
return &buffer[3]; // Reserve one zero
|
||||
}
|
||||
else
|
||||
return &buffer[length + offset];
|
||||
}
|
||||
else if (kk < -maxDecimalPlaces) {
|
||||
// Truncate to zero
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else if (length == 1) {
|
||||
// 1e30
|
||||
buffer[1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[2]);
|
||||
}
|
||||
else {
|
||||
// 1234e30 -> 1.234e33
|
||||
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||
buffer[1] = '.';
|
||||
buffer[length + 1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
|
||||
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
|
||||
Double d(value);
|
||||
if (d.IsZero()) {
|
||||
if (d.Sign())
|
||||
*buffer++ = '-'; // -0.0, Issue #289
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else {
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
value = -value;
|
||||
}
|
||||
int length, K;
|
||||
Grisu2(value, buffer, &length, &K);
|
||||
return Prettify(buffer, length, K, maxDecimalPlaces);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_DTOA_
|
||||
78
util/xpack/rapidjson/internal/ieee754.h
Executable file
78
util/xpack/rapidjson/internal/ieee754.h
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_IEEE754_
|
||||
#define RAPIDJSON_IEEE754_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
class Double {
|
||||
public:
|
||||
Double() {}
|
||||
Double(double d) : d_(d) {}
|
||||
Double(uint64_t u) : u_(u) {}
|
||||
|
||||
double Value() const { return d_; }
|
||||
uint64_t Uint64Value() const { return u_; }
|
||||
|
||||
double NextPositiveDouble() const {
|
||||
RAPIDJSON_ASSERT(!Sign());
|
||||
return Double(u_ + 1).Value();
|
||||
}
|
||||
|
||||
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||
|
||||
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
|
||||
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
|
||||
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
|
||||
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
|
||||
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||
|
||||
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||
|
||||
static int EffectiveSignificandSize(int order) {
|
||||
if (order >= -1021)
|
||||
return 53;
|
||||
else if (order <= -1074)
|
||||
return 0;
|
||||
else
|
||||
return order + 1074;
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kSignificandSize = 52;
|
||||
static const int kExponentBias = 0x3FF;
|
||||
static const int kDenormalExponent = 1 - kExponentBias;
|
||||
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
|
||||
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
union {
|
||||
double d_;
|
||||
uint64_t u_;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_IEEE754_
|
||||
308
util/xpack/rapidjson/internal/itoa.h
Executable file
308
util/xpack/rapidjson/internal/itoa.h
Executable file
|
|
@ -0,0 +1,308 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ITOA_
|
||||
#define RAPIDJSON_ITOA_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
inline const char* GetDigitsLut() {
|
||||
static const char cDigitsLut[200] = {
|
||||
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
|
||||
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
|
||||
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
|
||||
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
|
||||
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
|
||||
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
|
||||
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
|
||||
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
|
||||
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
|
||||
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
|
||||
};
|
||||
return cDigitsLut;
|
||||
}
|
||||
|
||||
inline char* u32toa(uint32_t value, char* buffer) {
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
|
||||
const char* cDigitsLut = GetDigitsLut();
|
||||
|
||||
if (value < 10000) {
|
||||
const uint32_t d1 = (value / 100) << 1;
|
||||
const uint32_t d2 = (value % 100) << 1;
|
||||
|
||||
if (value >= 1000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 100)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 10)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
}
|
||||
else if (value < 100000000) {
|
||||
// value = bbbbcccc
|
||||
const uint32_t b = value / 10000;
|
||||
const uint32_t c = value % 10000;
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
if (value >= 10000000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 1000000)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 100000)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
else {
|
||||
// value = aabbbbcccc in decimal
|
||||
|
||||
const uint32_t a = value / 100000000; // 1 to 42
|
||||
value %= 100000000;
|
||||
|
||||
if (a >= 10) {
|
||||
const unsigned i = a << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
|
||||
const uint32_t b = value / 10000; // 0 to 9999
|
||||
const uint32_t c = value % 10000; // 0 to 9999
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* i32toa(int32_t value, char* buffer) {
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
uint32_t u = static_cast<uint32_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
|
||||
return u32toa(u, buffer);
|
||||
}
|
||||
|
||||
inline char* u64toa(uint64_t value, char* buffer) {
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
const char* cDigitsLut = GetDigitsLut();
|
||||
const uint64_t kTen8 = 100000000;
|
||||
const uint64_t kTen9 = kTen8 * 10;
|
||||
const uint64_t kTen10 = kTen8 * 100;
|
||||
const uint64_t kTen11 = kTen8 * 1000;
|
||||
const uint64_t kTen12 = kTen8 * 10000;
|
||||
const uint64_t kTen13 = kTen8 * 100000;
|
||||
const uint64_t kTen14 = kTen8 * 1000000;
|
||||
const uint64_t kTen15 = kTen8 * 10000000;
|
||||
const uint64_t kTen16 = kTen8 * kTen8;
|
||||
|
||||
if (value < kTen8) {
|
||||
uint32_t v = static_cast<uint32_t>(value);
|
||||
if (v < 10000) {
|
||||
const uint32_t d1 = (v / 100) << 1;
|
||||
const uint32_t d2 = (v % 100) << 1;
|
||||
|
||||
if (v >= 1000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (v >= 100)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (v >= 10)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
}
|
||||
else {
|
||||
// value = bbbbcccc
|
||||
const uint32_t b = v / 10000;
|
||||
const uint32_t c = v % 10000;
|
||||
|
||||
const uint32_t d1 = (b / 100) << 1;
|
||||
const uint32_t d2 = (b % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c / 100) << 1;
|
||||
const uint32_t d4 = (c % 100) << 1;
|
||||
|
||||
if (value >= 10000000)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= 1000000)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= 100000)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
}
|
||||
}
|
||||
else if (value < kTen16) {
|
||||
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||
|
||||
const uint32_t b0 = v0 / 10000;
|
||||
const uint32_t c0 = v0 % 10000;
|
||||
|
||||
const uint32_t d1 = (b0 / 100) << 1;
|
||||
const uint32_t d2 = (b0 % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c0 / 100) << 1;
|
||||
const uint32_t d4 = (c0 % 100) << 1;
|
||||
|
||||
const uint32_t b1 = v1 / 10000;
|
||||
const uint32_t c1 = v1 % 10000;
|
||||
|
||||
const uint32_t d5 = (b1 / 100) << 1;
|
||||
const uint32_t d6 = (b1 % 100) << 1;
|
||||
|
||||
const uint32_t d7 = (c1 / 100) << 1;
|
||||
const uint32_t d8 = (c1 % 100) << 1;
|
||||
|
||||
if (value >= kTen15)
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
if (value >= kTen14)
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
if (value >= kTen13)
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
if (value >= kTen12)
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
if (value >= kTen11)
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
if (value >= kTen10)
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
if (value >= kTen9)
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
*buffer++ = cDigitsLut[d5];
|
||||
*buffer++ = cDigitsLut[d5 + 1];
|
||||
*buffer++ = cDigitsLut[d6];
|
||||
*buffer++ = cDigitsLut[d6 + 1];
|
||||
*buffer++ = cDigitsLut[d7];
|
||||
*buffer++ = cDigitsLut[d7 + 1];
|
||||
*buffer++ = cDigitsLut[d8];
|
||||
*buffer++ = cDigitsLut[d8 + 1];
|
||||
}
|
||||
else {
|
||||
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
|
||||
value %= kTen16;
|
||||
|
||||
if (a < 10)
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||
else if (a < 100) {
|
||||
const uint32_t i = a << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else if (a < 1000) {
|
||||
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
|
||||
|
||||
const uint32_t i = (a % 100) << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
}
|
||||
else {
|
||||
const uint32_t i = (a / 100) << 1;
|
||||
const uint32_t j = (a % 100) << 1;
|
||||
*buffer++ = cDigitsLut[i];
|
||||
*buffer++ = cDigitsLut[i + 1];
|
||||
*buffer++ = cDigitsLut[j];
|
||||
*buffer++ = cDigitsLut[j + 1];
|
||||
}
|
||||
|
||||
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||
|
||||
const uint32_t b0 = v0 / 10000;
|
||||
const uint32_t c0 = v0 % 10000;
|
||||
|
||||
const uint32_t d1 = (b0 / 100) << 1;
|
||||
const uint32_t d2 = (b0 % 100) << 1;
|
||||
|
||||
const uint32_t d3 = (c0 / 100) << 1;
|
||||
const uint32_t d4 = (c0 % 100) << 1;
|
||||
|
||||
const uint32_t b1 = v1 / 10000;
|
||||
const uint32_t c1 = v1 % 10000;
|
||||
|
||||
const uint32_t d5 = (b1 / 100) << 1;
|
||||
const uint32_t d6 = (b1 % 100) << 1;
|
||||
|
||||
const uint32_t d7 = (c1 / 100) << 1;
|
||||
const uint32_t d8 = (c1 % 100) << 1;
|
||||
|
||||
*buffer++ = cDigitsLut[d1];
|
||||
*buffer++ = cDigitsLut[d1 + 1];
|
||||
*buffer++ = cDigitsLut[d2];
|
||||
*buffer++ = cDigitsLut[d2 + 1];
|
||||
*buffer++ = cDigitsLut[d3];
|
||||
*buffer++ = cDigitsLut[d3 + 1];
|
||||
*buffer++ = cDigitsLut[d4];
|
||||
*buffer++ = cDigitsLut[d4 + 1];
|
||||
*buffer++ = cDigitsLut[d5];
|
||||
*buffer++ = cDigitsLut[d5 + 1];
|
||||
*buffer++ = cDigitsLut[d6];
|
||||
*buffer++ = cDigitsLut[d6 + 1];
|
||||
*buffer++ = cDigitsLut[d7];
|
||||
*buffer++ = cDigitsLut[d7 + 1];
|
||||
*buffer++ = cDigitsLut[d8];
|
||||
*buffer++ = cDigitsLut[d8 + 1];
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* i64toa(int64_t value, char* buffer) {
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
uint64_t u = static_cast<uint64_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
|
||||
return u64toa(u, buffer);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ITOA_
|
||||
186
util/xpack/rapidjson/internal/meta.h
Executable file
186
util/xpack/rapidjson/internal/meta.h
Executable file
|
|
@ -0,0 +1,186 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(6334)
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
//@cond RAPIDJSON_INTERNAL
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BoolType, TrueType, FalseType
|
||||
//
|
||||
template <bool Cond> struct BoolType {
|
||||
static const bool Value = Cond;
|
||||
typedef BoolType Type;
|
||||
};
|
||||
typedef BoolType<true> TrueType;
|
||||
typedef BoolType<false> FalseType;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||
//
|
||||
|
||||
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||
|
||||
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||
template <> struct AndExprCond<true, true> : TrueType {};
|
||||
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||
template <> struct OrExprCond<false, false> : FalseType {};
|
||||
|
||||
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AddConst, MaybeAddConst, RemoveConst
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||
//
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst
|
||||
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsBaseOf
|
||||
//
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||
|
||||
#else // simplified version adopted from Boost
|
||||
|
||||
template<typename B, typename D> struct IsBaseOfImpl {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||
|
||||
typedef char (&Yes)[1];
|
||||
typedef char (&No) [2];
|
||||
|
||||
template <typename T>
|
||||
static Yes Check(const D*, T);
|
||||
static No Check(const B*, int);
|
||||
|
||||
struct Host {
|
||||
operator const B*() const;
|
||||
operator const D*();
|
||||
};
|
||||
|
||||
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||
};
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||
|
||||
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EnableIf / DisableIf
|
||||
//
|
||||
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeTag {};
|
||||
template <typename T> struct RemoveSfinaeTag;
|
||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_DISABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
//@endcond
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||
55
util/xpack/rapidjson/internal/pow10.h
Executable file
55
util/xpack/rapidjson/internal/pow10.h
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Computes integer powers of 10 in double (10.0^n).
|
||||
/*! This function uses lookup table for fast and accurate results.
|
||||
\param n non-negative exponent. Must <= 308.
|
||||
\return 10.0^n
|
||||
*/
|
||||
inline double Pow10(int n) {
|
||||
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
|
||||
1e+0,
|
||||
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||
};
|
||||
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
|
||||
return e[n];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
740
util/xpack/rapidjson/internal/regex.h
Executable file
740
util/xpack/rapidjson/internal/regex.h
Executable file
|
|
@ -0,0 +1,740 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
|
||||
#define RAPIDJSON_INTERNAL_REGEX_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "../stream.h"
|
||||
#include "stack.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||
#elif defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#if __GNUC__ >= 7
|
||||
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_REGEX_VERBOSE
|
||||
#define RAPIDJSON_REGEX_VERBOSE 0
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DecodedStream
|
||||
|
||||
template <typename SourceStream, typename Encoding>
|
||||
class DecodedStream {
|
||||
public:
|
||||
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
|
||||
unsigned Peek() { return codepoint_; }
|
||||
unsigned Take() {
|
||||
unsigned c = codepoint_;
|
||||
if (c) // No further decoding when '\0'
|
||||
Decode();
|
||||
return c;
|
||||
}
|
||||
|
||||
private:
|
||||
void Decode() {
|
||||
if (!Encoding::Decode(ss_, &codepoint_))
|
||||
codepoint_ = 0;
|
||||
}
|
||||
|
||||
SourceStream& ss_;
|
||||
unsigned codepoint_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericRegex
|
||||
|
||||
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
|
||||
static const SizeType kRegexInvalidRange = ~SizeType(0);
|
||||
|
||||
template <typename Encoding, typename Allocator>
|
||||
class GenericRegexSearch;
|
||||
|
||||
//! Regular expression engine with subset of ECMAscript grammar.
|
||||
/*!
|
||||
Supported regular expression syntax:
|
||||
- \c ab Concatenation
|
||||
- \c a|b Alternation
|
||||
- \c a? Zero or one
|
||||
- \c a* Zero or more
|
||||
- \c a+ One or more
|
||||
- \c a{3} Exactly 3 times
|
||||
- \c a{3,} At least 3 times
|
||||
- \c a{3,5} 3 to 5 times
|
||||
- \c (ab) Grouping
|
||||
- \c ^a At the beginning
|
||||
- \c a$ At the end
|
||||
- \c . Any character
|
||||
- \c [abc] Character classes
|
||||
- \c [a-c] Character class range
|
||||
- \c [a-z0-9_] Character class combination
|
||||
- \c [^abc] Negated character classes
|
||||
- \c [^a-c] Negated character class range
|
||||
- \c [\b] Backspace (U+0008)
|
||||
- \c \\| \\\\ ... Escape characters
|
||||
- \c \\f Form feed (U+000C)
|
||||
- \c \\n Line feed (U+000A)
|
||||
- \c \\r Carriage return (U+000D)
|
||||
- \c \\t Tab (U+0009)
|
||||
- \c \\v Vertical tab (U+000B)
|
||||
|
||||
\note This is a Thompson NFA engine, implemented with reference to
|
||||
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
|
||||
https://swtch.com/~rsc/regexp/regexp1.html
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericRegex {
|
||||
public:
|
||||
typedef Encoding EncodingType;
|
||||
typedef typename Encoding::Ch Ch;
|
||||
template <typename, typename> friend class GenericRegexSearch;
|
||||
|
||||
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
||||
ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
|
||||
states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
||||
anchorBegin_(), anchorEnd_()
|
||||
{
|
||||
GenericStringStream<Encoding> ss(source);
|
||||
DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
|
||||
Parse(ds);
|
||||
}
|
||||
|
||||
~GenericRegex()
|
||||
{
|
||||
RAPIDJSON_DELETE(ownAllocator_);
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return root_ != kRegexInvalidState;
|
||||
}
|
||||
|
||||
private:
|
||||
enum Operator {
|
||||
kZeroOrOne,
|
||||
kZeroOrMore,
|
||||
kOneOrMore,
|
||||
kConcatenation,
|
||||
kAlternation,
|
||||
kLeftParenthesis
|
||||
};
|
||||
|
||||
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
|
||||
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
|
||||
static const unsigned kRangeNegationFlag = 0x80000000;
|
||||
|
||||
struct Range {
|
||||
unsigned start; //
|
||||
unsigned end;
|
||||
SizeType next;
|
||||
};
|
||||
|
||||
struct State {
|
||||
SizeType out; //!< Equals to kInvalid for matching state
|
||||
SizeType out1; //!< Equals to non-kInvalid for split
|
||||
SizeType rangeStart;
|
||||
unsigned codepoint;
|
||||
};
|
||||
|
||||
struct Frag {
|
||||
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
|
||||
SizeType start;
|
||||
SizeType out; //!< link-list of all output states
|
||||
SizeType minIndex;
|
||||
};
|
||||
|
||||
State& GetState(SizeType index) {
|
||||
RAPIDJSON_ASSERT(index < stateCount_);
|
||||
return states_.template Bottom<State>()[index];
|
||||
}
|
||||
|
||||
const State& GetState(SizeType index) const {
|
||||
RAPIDJSON_ASSERT(index < stateCount_);
|
||||
return states_.template Bottom<State>()[index];
|
||||
}
|
||||
|
||||
Range& GetRange(SizeType index) {
|
||||
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||
return ranges_.template Bottom<Range>()[index];
|
||||
}
|
||||
|
||||
const Range& GetRange(SizeType index) const {
|
||||
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||
return ranges_.template Bottom<Range>()[index];
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
void Parse(DecodedStream<InputStream, Encoding>& ds) {
|
||||
Stack<Allocator> operandStack(allocator_, 256); // Frag
|
||||
Stack<Allocator> operatorStack(allocator_, 256); // Operator
|
||||
Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
|
||||
|
||||
*atomCountStack.template Push<unsigned>() = 0;
|
||||
|
||||
unsigned codepoint;
|
||||
while (ds.Peek() != 0) {
|
||||
switch (codepoint = ds.Take()) {
|
||||
case '^':
|
||||
anchorBegin_ = true;
|
||||
break;
|
||||
|
||||
case '$':
|
||||
anchorEnd_ = true;
|
||||
break;
|
||||
|
||||
case '|':
|
||||
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
*operatorStack.template Push<Operator>() = kAlternation;
|
||||
*atomCountStack.template Top<unsigned>() = 0;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
*operatorStack.template Push<Operator>() = kLeftParenthesis;
|
||||
*atomCountStack.template Push<unsigned>() = 0;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
if (operatorStack.Empty())
|
||||
return;
|
||||
operatorStack.template Pop<Operator>(1);
|
||||
atomCountStack.template Pop<unsigned>(1);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
if (!Eval(operandStack, kZeroOrOne))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (!Eval(operandStack, kZeroOrMore))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (!Eval(operandStack, kOneOrMore))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '{':
|
||||
{
|
||||
unsigned n, m;
|
||||
if (!ParseUnsigned(ds, &n))
|
||||
return;
|
||||
|
||||
if (ds.Peek() == ',') {
|
||||
ds.Take();
|
||||
if (ds.Peek() == '}')
|
||||
m = kInfinityQuantifier;
|
||||
else if (!ParseUnsigned(ds, &m) || m < n)
|
||||
return;
|
||||
}
|
||||
else
|
||||
m = n;
|
||||
|
||||
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
|
||||
return;
|
||||
ds.Take();
|
||||
}
|
||||
break;
|
||||
|
||||
case '.':
|
||||
PushOperand(operandStack, kAnyCharacterClass);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
{
|
||||
SizeType range;
|
||||
if (!ParseRange(ds, &range))
|
||||
return;
|
||||
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
|
||||
GetState(s).rangeStart = range;
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||
}
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
break;
|
||||
|
||||
case '\\': // Escape character
|
||||
if (!CharacterEscape(ds, &codepoint))
|
||||
return; // Unsupported escape character
|
||||
// fall through to default
|
||||
|
||||
default: // Pattern character
|
||||
PushOperand(operandStack, codepoint);
|
||||
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||
}
|
||||
}
|
||||
|
||||
while (!operatorStack.Empty())
|
||||
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||
return;
|
||||
|
||||
// Link the operand to matching state.
|
||||
if (operandStack.GetSize() == sizeof(Frag)) {
|
||||
Frag* e = operandStack.template Pop<Frag>(1);
|
||||
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
|
||||
root_ = e->start;
|
||||
|
||||
#if RAPIDJSON_REGEX_VERBOSE
|
||||
printf("root: %d\n", root_);
|
||||
for (SizeType i = 0; i < stateCount_ ; i++) {
|
||||
State& s = GetState(i);
|
||||
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
|
||||
State* s = states_.template Push<State>();
|
||||
s->out = out;
|
||||
s->out1 = out1;
|
||||
s->codepoint = codepoint;
|
||||
s->rangeStart = kRegexInvalidRange;
|
||||
return stateCount_++;
|
||||
}
|
||||
|
||||
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
|
||||
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||
}
|
||||
|
||||
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
|
||||
if (*atomCountStack.template Top<unsigned>())
|
||||
*operatorStack.template Push<Operator>() = kConcatenation;
|
||||
(*atomCountStack.template Top<unsigned>())++;
|
||||
}
|
||||
|
||||
SizeType Append(SizeType l1, SizeType l2) {
|
||||
SizeType old = l1;
|
||||
while (GetState(l1).out != kRegexInvalidState)
|
||||
l1 = GetState(l1).out;
|
||||
GetState(l1).out = l2;
|
||||
return old;
|
||||
}
|
||||
|
||||
void Patch(SizeType l, SizeType s) {
|
||||
for (SizeType next; l != kRegexInvalidState; l = next) {
|
||||
next = GetState(l).out;
|
||||
GetState(l).out = s;
|
||||
}
|
||||
}
|
||||
|
||||
bool Eval(Stack<Allocator>& operandStack, Operator op) {
|
||||
switch (op) {
|
||||
case kConcatenation:
|
||||
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
|
||||
{
|
||||
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||
Patch(e1.out, e2.start);
|
||||
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
|
||||
}
|
||||
return true;
|
||||
|
||||
case kAlternation:
|
||||
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
|
||||
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(e1.start, e2.start, 0);
|
||||
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kZeroOrOne:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kZeroOrMore:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
Patch(e.out, s);
|
||||
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case kOneOrMore:
|
||||
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||
Frag e = *operandStack.template Pop<Frag>(1);
|
||||
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||
Patch(e.out, s);
|
||||
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
// syntax error (e.g. unclosed kLeftParenthesis)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
|
||||
RAPIDJSON_ASSERT(n <= m);
|
||||
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
|
||||
|
||||
if (n == 0) {
|
||||
if (m == 0) // a{0} not support
|
||||
return false;
|
||||
else if (m == kInfinityQuantifier)
|
||||
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
|
||||
else {
|
||||
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
|
||||
for (unsigned i = 0; i < m - 1; i++)
|
||||
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
|
||||
for (unsigned i = 0; i < m - 1; i++)
|
||||
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
|
||||
CloneTopOperand(operandStack);
|
||||
|
||||
if (m == kInfinityQuantifier)
|
||||
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
|
||||
else if (m > n) {
|
||||
CloneTopOperand(operandStack); // a{3,5} -> a a a a
|
||||
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
|
||||
for (unsigned i = n; i < m - 1; i++)
|
||||
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
|
||||
for (unsigned i = n; i < m; i++)
|
||||
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n - 1; i++)
|
||||
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
|
||||
|
||||
void CloneTopOperand(Stack<Allocator>& operandStack) {
|
||||
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
|
||||
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
|
||||
State* s = states_.template Push<State>(count);
|
||||
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
|
||||
for (SizeType j = 0; j < count; j++) {
|
||||
if (s[j].out != kRegexInvalidState)
|
||||
s[j].out += count;
|
||||
if (s[j].out1 != kRegexInvalidState)
|
||||
s[j].out1 += count;
|
||||
}
|
||||
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
|
||||
stateCount_ += count;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
|
||||
unsigned r = 0;
|
||||
if (ds.Peek() < '0' || ds.Peek() > '9')
|
||||
return false;
|
||||
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
|
||||
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
|
||||
return false; // overflow
|
||||
r = r * 10 + (ds.Take() - '0');
|
||||
}
|
||||
*u = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
|
||||
bool isBegin = true;
|
||||
bool negate = false;
|
||||
int step = 0;
|
||||
SizeType start = kRegexInvalidRange;
|
||||
SizeType current = kRegexInvalidRange;
|
||||
unsigned codepoint;
|
||||
while ((codepoint = ds.Take()) != 0) {
|
||||
if (isBegin) {
|
||||
isBegin = false;
|
||||
if (codepoint == '^') {
|
||||
negate = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (codepoint) {
|
||||
case ']':
|
||||
if (start == kRegexInvalidRange)
|
||||
return false; // Error: nothing inside []
|
||||
if (step == 2) { // Add trailing '-'
|
||||
SizeType r = NewRange('-');
|
||||
RAPIDJSON_ASSERT(current != kRegexInvalidRange);
|
||||
GetRange(current).next = r;
|
||||
}
|
||||
if (negate)
|
||||
GetRange(start).start |= kRangeNegationFlag;
|
||||
*range = start;
|
||||
return true;
|
||||
|
||||
case '\\':
|
||||
if (ds.Peek() == 'b') {
|
||||
ds.Take();
|
||||
codepoint = 0x0008; // Escape backspace character
|
||||
}
|
||||
else if (!CharacterEscape(ds, &codepoint))
|
||||
return false;
|
||||
// fall through to default
|
||||
|
||||
default:
|
||||
switch (step) {
|
||||
case 1:
|
||||
if (codepoint == '-') {
|
||||
step++;
|
||||
break;
|
||||
}
|
||||
// fall through to step 0 for other characters
|
||||
|
||||
case 0:
|
||||
{
|
||||
SizeType r = NewRange(codepoint);
|
||||
if (current != kRegexInvalidRange)
|
||||
GetRange(current).next = r;
|
||||
if (start == kRegexInvalidRange)
|
||||
start = r;
|
||||
current = r;
|
||||
}
|
||||
step = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
RAPIDJSON_ASSERT(step == 2);
|
||||
GetRange(current).end = codepoint;
|
||||
step = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SizeType NewRange(unsigned codepoint) {
|
||||
Range* r = ranges_.template Push<Range>();
|
||||
r->start = r->end = codepoint;
|
||||
r->next = kRegexInvalidRange;
|
||||
return rangeCount_++;
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
|
||||
unsigned codepoint;
|
||||
switch (codepoint = ds.Take()) {
|
||||
case '^':
|
||||
case '$':
|
||||
case '|':
|
||||
case '(':
|
||||
case ')':
|
||||
case '?':
|
||||
case '*':
|
||||
case '+':
|
||||
case '.':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '\\':
|
||||
*escapedCodepoint = codepoint; return true;
|
||||
case 'f': *escapedCodepoint = 0x000C; return true;
|
||||
case 'n': *escapedCodepoint = 0x000A; return true;
|
||||
case 'r': *escapedCodepoint = 0x000D; return true;
|
||||
case 't': *escapedCodepoint = 0x0009; return true;
|
||||
case 'v': *escapedCodepoint = 0x000B; return true;
|
||||
default:
|
||||
return false; // Unsupported escape character
|
||||
}
|
||||
}
|
||||
|
||||
Allocator* ownAllocator_;
|
||||
Allocator* allocator_;
|
||||
Stack<Allocator> states_;
|
||||
Stack<Allocator> ranges_;
|
||||
SizeType root_;
|
||||
SizeType stateCount_;
|
||||
SizeType rangeCount_;
|
||||
|
||||
static const unsigned kInfinityQuantifier = ~0u;
|
||||
|
||||
// For SearchWithAnchoring()
|
||||
bool anchorBegin_;
|
||||
bool anchorEnd_;
|
||||
};
|
||||
|
||||
template <typename RegexType, typename Allocator = CrtAllocator>
|
||||
class GenericRegexSearch {
|
||||
public:
|
||||
typedef typename RegexType::EncodingType Encoding;
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
|
||||
regex_(regex), allocator_(allocator), ownAllocator_(0),
|
||||
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
|
||||
{
|
||||
RAPIDJSON_ASSERT(regex_.IsValid());
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
||||
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
|
||||
state0_.template Reserve<SizeType>(regex_.stateCount_);
|
||||
state1_.template Reserve<SizeType>(regex_.stateCount_);
|
||||
}
|
||||
|
||||
~GenericRegexSearch() {
|
||||
Allocator::Free(stateSet_);
|
||||
RAPIDJSON_DELETE(ownAllocator_);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool Match(InputStream& is) {
|
||||
return SearchWithAnchoring(is, true, true);
|
||||
}
|
||||
|
||||
bool Match(const Ch* s) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
return Match(is);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
bool Search(InputStream& is) {
|
||||
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
|
||||
}
|
||||
|
||||
bool Search(const Ch* s) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
return Search(is);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename RegexType::State State;
|
||||
typedef typename RegexType::Range Range;
|
||||
|
||||
template <typename InputStream>
|
||||
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
|
||||
DecodedStream<InputStream, Encoding> ds(is);
|
||||
|
||||
state0_.Clear();
|
||||
Stack<Allocator> *current = &state0_, *next = &state1_;
|
||||
const size_t stateSetSize = GetStateSetSize();
|
||||
std::memset(stateSet_, 0, stateSetSize);
|
||||
|
||||
bool matched = AddState(*current, regex_.root_);
|
||||
unsigned codepoint;
|
||||
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
|
||||
std::memset(stateSet_, 0, stateSetSize);
|
||||
next->Clear();
|
||||
matched = false;
|
||||
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
|
||||
const State& sr = regex_.GetState(*s);
|
||||
if (sr.codepoint == codepoint ||
|
||||
sr.codepoint == RegexType::kAnyCharacterClass ||
|
||||
(sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
|
||||
{
|
||||
matched = AddState(*next, sr.out) || matched;
|
||||
if (!anchorEnd && matched)
|
||||
return true;
|
||||
}
|
||||
if (!anchorBegin)
|
||||
AddState(*next, regex_.root_);
|
||||
}
|
||||
internal::Swap(current, next);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
size_t GetStateSetSize() const {
|
||||
return (regex_.stateCount_ + 31) / 32 * 4;
|
||||
}
|
||||
|
||||
// Return whether the added states is a match state
|
||||
bool AddState(Stack<Allocator>& l, SizeType index) {
|
||||
RAPIDJSON_ASSERT(index != kRegexInvalidState);
|
||||
|
||||
const State& s = regex_.GetState(index);
|
||||
if (s.out1 != kRegexInvalidState) { // Split
|
||||
bool matched = AddState(l, s.out);
|
||||
return AddState(l, s.out1) || matched;
|
||||
}
|
||||
else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
|
||||
stateSet_[index >> 5] |= (1u << (index & 31));
|
||||
*l.template PushUnsafe<SizeType>() = index;
|
||||
}
|
||||
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
|
||||
}
|
||||
|
||||
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
|
||||
bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
|
||||
while (rangeIndex != kRegexInvalidRange) {
|
||||
const Range& r = regex_.GetRange(rangeIndex);
|
||||
if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
|
||||
return yes;
|
||||
rangeIndex = r.next;
|
||||
}
|
||||
return !yes;
|
||||
}
|
||||
|
||||
const RegexType& regex_;
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
Stack<Allocator> state0_;
|
||||
Stack<Allocator> state1_;
|
||||
uint32_t* stateSet_;
|
||||
};
|
||||
|
||||
typedef GenericRegex<UTF8<> > Regex;
|
||||
typedef GenericRegexSearch<Regex> RegexSearch;
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_REGEX_H_
|
||||
232
util/xpack/rapidjson/internal/stack.h
Executable file
232
util/xpack/rapidjson/internal/stack.h
Executable file
|
|
@ -0,0 +1,232 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "swap.h"
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack(Stack&& rhs)
|
||||
: allocator_(rhs.allocator_),
|
||||
ownAllocator_(rhs.ownAllocator_),
|
||||
stack_(rhs.stack_),
|
||||
stackTop_(rhs.stackTop_),
|
||||
stackEnd_(rhs.stackEnd_),
|
||||
initialCapacity_(rhs.initialCapacity_)
|
||||
{
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Stack() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack& operator=(Stack&& rhs) {
|
||||
if (&rhs != this)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
allocator_ = rhs.allocator_;
|
||||
ownAllocator_ = rhs.ownAllocator_;
|
||||
stack_ = rhs.stack_;
|
||||
stackTop_ = rhs.stackTop_;
|
||||
stackEnd_ = rhs.stackEnd_;
|
||||
initialCapacity_ = rhs.initialCapacity_;
|
||||
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(stack_, rhs.stack_);
|
||||
internal::Swap(stackTop_, rhs.stackTop_);
|
||||
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||
}
|
||||
|
||||
void Clear() { stackTop_ = stack_; }
|
||||
|
||||
void ShrinkToFit() {
|
||||
if (Empty()) {
|
||||
// If the stack is empty, completely deallocate the memory.
|
||||
Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
|
||||
stack_ = 0;
|
||||
stackTop_ = 0;
|
||||
stackEnd_ = 0;
|
||||
}
|
||||
else
|
||||
Resize(GetSize());
|
||||
}
|
||||
|
||||
// Optimization note: try to minimize the size of this function for force inline.
|
||||
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
|
||||
Expand<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||
Reserve<T>(count);
|
||||
return PushUnsafe<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||
RAPIDJSON_ASSERT(stackTop_);
|
||||
RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
|
||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||
stackTop_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stackTop_ -= count * sizeof(T);
|
||||
return reinterpret_cast<T*>(stackTop_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Top() const {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
template<typename T>
|
||||
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
bool HasAllocator() const {
|
||||
return allocator_ != 0;
|
||||
}
|
||||
|
||||
Allocator& GetAllocator() {
|
||||
RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
|
||||
bool Empty() const { return stackTop_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void Expand(size_t count) {
|
||||
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||
size_t newCapacity;
|
||||
if (stack_ == 0) {
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
||||
newCapacity = initialCapacity_;
|
||||
} else {
|
||||
newCapacity = GetCapacity();
|
||||
newCapacity += (newCapacity + 1) / 2;
|
||||
}
|
||||
size_t newSize = GetSize() + sizeof(T) * count;
|
||||
if (newCapacity < newSize)
|
||||
newCapacity = newSize;
|
||||
|
||||
Resize(newCapacity);
|
||||
}
|
||||
|
||||
void Resize(size_t newCapacity) {
|
||||
const size_t size = GetSize(); // Backup the current size
|
||||
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||
stackTop_ = stack_ + size;
|
||||
stackEnd_ = stack_ + newCapacity;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
Allocator::Free(stack_);
|
||||
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
char *stack_;
|
||||
char *stackTop_;
|
||||
char *stackEnd_;
|
||||
size_t initialCapacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
69
util/xpack/rapidjson/internal/strfunc.h
Executable file
69
util/xpack/rapidjson/internal/strfunc.h
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
#include "../stream.h"
|
||||
#include <cwchar>
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom strlen() which works on different character types.
|
||||
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||
\param s Null-terminated input string.
|
||||
\return Number of characters in the string.
|
||||
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
RAPIDJSON_ASSERT(s != 0);
|
||||
const Ch* p = s;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline SizeType StrLen(const char* s) {
|
||||
return SizeType(std::strlen(s));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline SizeType StrLen(const wchar_t* s) {
|
||||
return SizeType(std::wcslen(s));
|
||||
}
|
||||
|
||||
//! Returns number of code points in a encoded string.
|
||||
template<typename Encoding>
|
||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||
RAPIDJSON_ASSERT(s != 0);
|
||||
RAPIDJSON_ASSERT(outCount != 0);
|
||||
GenericStringStream<Encoding> is(s);
|
||||
const typename Encoding::Ch* end = s + length;
|
||||
SizeType count = 0;
|
||||
while (is.src_ < end) {
|
||||
unsigned codepoint;
|
||||
if (!Encoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
*outCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
290
util/xpack/rapidjson/internal/strtod.h
Executable file
290
util/xpack/rapidjson/internal/strtod.h
Executable file
|
|
@ -0,0 +1,290 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_STRTOD_
|
||||
#define RAPIDJSON_STRTOD_
|
||||
|
||||
#include "ieee754.h"
|
||||
#include "biginteger.h"
|
||||
#include "diyfp.h"
|
||||
#include "pow10.h"
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
inline double FastPath(double significand, int exp) {
|
||||
if (exp < -308)
|
||||
return 0.0;
|
||||
else if (exp >= 0)
|
||||
return significand * internal::Pow10(exp);
|
||||
else
|
||||
return significand / internal::Pow10(-exp);
|
||||
}
|
||||
|
||||
inline double StrtodNormalPrecision(double d, int p) {
|
||||
if (p < -308) {
|
||||
// Prevent expSum < -308, making Pow10(p) = 0
|
||||
d = FastPath(d, -308);
|
||||
d = FastPath(d, p + 308);
|
||||
}
|
||||
else
|
||||
d = FastPath(d, p);
|
||||
return d;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Min3(T a, T b, T c) {
|
||||
T m = a;
|
||||
if (m > b) m = b;
|
||||
if (m > c) m = c;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||
const Double db(b);
|
||||
const uint64_t bInt = db.IntegerSignificand();
|
||||
const int bExp = db.IntegerExponent();
|
||||
const int hExp = bExp - 1;
|
||||
|
||||
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
|
||||
|
||||
// Adjust for decimal exponent
|
||||
if (dExp >= 0) {
|
||||
dS_Exp2 += dExp;
|
||||
dS_Exp5 += dExp;
|
||||
}
|
||||
else {
|
||||
bS_Exp2 -= dExp;
|
||||
bS_Exp5 -= dExp;
|
||||
hS_Exp2 -= dExp;
|
||||
hS_Exp5 -= dExp;
|
||||
}
|
||||
|
||||
// Adjust for binary exponent
|
||||
if (bExp >= 0)
|
||||
bS_Exp2 += bExp;
|
||||
else {
|
||||
dS_Exp2 -= bExp;
|
||||
hS_Exp2 -= bExp;
|
||||
}
|
||||
|
||||
// Adjust for half ulp exponent
|
||||
if (hExp >= 0)
|
||||
hS_Exp2 += hExp;
|
||||
else {
|
||||
dS_Exp2 -= hExp;
|
||||
bS_Exp2 -= hExp;
|
||||
}
|
||||
|
||||
// Remove common power of two factor from all three scaled values
|
||||
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
|
||||
dS_Exp2 -= common_Exp2;
|
||||
bS_Exp2 -= common_Exp2;
|
||||
hS_Exp2 -= common_Exp2;
|
||||
|
||||
BigInteger dS = d;
|
||||
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||
|
||||
BigInteger bS(bInt);
|
||||
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||
|
||||
BigInteger hS(1);
|
||||
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||
|
||||
BigInteger delta(0);
|
||||
dS.Difference(bS, &delta);
|
||||
|
||||
return delta.Compare(hS);
|
||||
}
|
||||
|
||||
inline bool StrtodFast(double d, int p, double* result) {
|
||||
// Use fast path for string-to-double conversion if possible
|
||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
if (p > 22 && p < 22 + 16) {
|
||||
// Fast Path Cases In Disguise
|
||||
d *= internal::Pow10(p - 22);
|
||||
p = 22;
|
||||
}
|
||||
|
||||
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||
*result = FastPath(d, p);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute an approximation and see if it is within 1/2 ULP
|
||||
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
|
||||
uint64_t significand = 0;
|
||||
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||
for (; i < dLen; i++) {
|
||||
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||
break;
|
||||
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||
}
|
||||
|
||||
if (i < dLen && decimals[i] >= '5') // Rounding
|
||||
significand++;
|
||||
|
||||
int remaining = dLen - i;
|
||||
const int kUlpShift = 3;
|
||||
const int kUlp = 1 << kUlpShift;
|
||||
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||
|
||||
DiyFp v(significand, 0);
|
||||
v = v.Normalize();
|
||||
error <<= -v.e;
|
||||
|
||||
dExp += remaining;
|
||||
|
||||
int actualExp;
|
||||
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||
if (actualExp != dExp) {
|
||||
static const DiyFp kPow10[] = {
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
|
||||
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
|
||||
};
|
||||
int adjustment = dExp - actualExp;
|
||||
RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
|
||||
v = v * kPow10[adjustment - 1];
|
||||
if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
|
||||
error += kUlp / 2;
|
||||
}
|
||||
|
||||
v = v * cachedPower;
|
||||
|
||||
error += kUlp + (error == 0 ? 0 : 1);
|
||||
|
||||
const int oldExp = v.e;
|
||||
v = v.Normalize();
|
||||
error <<= oldExp - v.e;
|
||||
|
||||
const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
|
||||
int precisionSize = 64 - effectiveSignificandSize;
|
||||
if (precisionSize + kUlpShift >= 64) {
|
||||
int scaleExp = (precisionSize + kUlpShift) - 63;
|
||||
v.f >>= scaleExp;
|
||||
v.e += scaleExp;
|
||||
error = (error >> scaleExp) + 1 + kUlp;
|
||||
precisionSize -= scaleExp;
|
||||
}
|
||||
|
||||
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
|
||||
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||
rounded.f++;
|
||||
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||
rounded.f >>= 1;
|
||||
rounded.e++;
|
||||
}
|
||||
}
|
||||
|
||||
*result = rounded.ToDouble();
|
||||
|
||||
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||
}
|
||||
|
||||
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
|
||||
RAPIDJSON_ASSERT(dLen >= 0);
|
||||
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
|
||||
Double a(approx);
|
||||
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||
if (cmp < 0)
|
||||
return a.Value(); // within half ULP
|
||||
else if (cmp == 0) {
|
||||
// Round towards even
|
||||
if (a.Significand() & 1)
|
||||
return a.NextPositiveDouble();
|
||||
else
|
||||
return a.Value();
|
||||
}
|
||||
else // adjustment
|
||||
return a.NextPositiveDouble();
|
||||
}
|
||||
|
||||
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||
RAPIDJSON_ASSERT(d >= 0.0);
|
||||
RAPIDJSON_ASSERT(length >= 1);
|
||||
|
||||
double result = 0.0;
|
||||
if (StrtodFast(d, p, &result))
|
||||
return result;
|
||||
|
||||
RAPIDJSON_ASSERT(length <= INT_MAX);
|
||||
int dLen = static_cast<int>(length);
|
||||
|
||||
RAPIDJSON_ASSERT(length >= decimalPosition);
|
||||
RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
|
||||
int dExpAdjust = static_cast<int>(length - decimalPosition);
|
||||
|
||||
RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
|
||||
int dExp = exp - dExpAdjust;
|
||||
|
||||
// Make sure length+dExp does not overflow
|
||||
RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
|
||||
|
||||
// Trim leading zeros
|
||||
while (dLen > 0 && *decimals == '0') {
|
||||
dLen--;
|
||||
decimals++;
|
||||
}
|
||||
|
||||
// Trim trailing zeros
|
||||
while (dLen > 0 && decimals[dLen - 1] == '0') {
|
||||
dLen--;
|
||||
dExp++;
|
||||
}
|
||||
|
||||
if (dLen == 0) { // Buffer only contains zeros.
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Trim right-most digits
|
||||
const int kMaxDecimalDigit = 767 + 1;
|
||||
if (dLen > kMaxDecimalDigit) {
|
||||
dExp += dLen - kMaxDecimalDigit;
|
||||
dLen = kMaxDecimalDigit;
|
||||
}
|
||||
|
||||
// If too small, underflow to zero.
|
||||
// Any x <= 10^-324 is interpreted as zero.
|
||||
if (dLen + dExp <= -324)
|
||||
return 0.0;
|
||||
|
||||
// If too large, overflow to infinity.
|
||||
// Any x >= 10^309 is interpreted as +infinity.
|
||||
if (dLen + dExp > 309)
|
||||
return std::numeric_limits<double>::infinity();
|
||||
|
||||
if (StrtodDiyFp(decimals, dLen, dExp, &result))
|
||||
return result;
|
||||
|
||||
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||
return StrtodBigInteger(result, decimals, dLen, dExp);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_STRTOD_
|
||||
46
util/xpack/rapidjson/internal/swap.h
Executable file
46
util/xpack/rapidjson/internal/swap.h
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||
\note This has the same semantics as std::swap().
|
||||
*/
|
||||
template <typename T>
|
||||
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
||||
127
util/xpack/rapidjson/istreamwrapper.h
Executable file
127
util/xpack/rapidjson/istreamwrapper.h
Executable file
|
|
@ -0,0 +1,127 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
#define RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#elif defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
|
||||
/*!
|
||||
The classes can be wrapped including but not limited to:
|
||||
|
||||
- \c std::istringstream
|
||||
- \c std::stringstream
|
||||
- \c std::wistringstream
|
||||
- \c std::wstringstream
|
||||
- \c std::ifstream
|
||||
- \c std::fstream
|
||||
- \c std::wifstream
|
||||
- \c std::wfstream
|
||||
|
||||
\tparam StreamType Class derived from \c std::basic_istream.
|
||||
*/
|
||||
|
||||
template <typename StreamType>
|
||||
class BasicIStreamWrapper {
|
||||
public:
|
||||
typedef typename StreamType::char_type Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param stream stream opened for read.
|
||||
*/
|
||||
BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
Read();
|
||||
}
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param stream stream opened for read.
|
||||
\param buffer user-supplied buffer.
|
||||
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||
*/
|
||||
BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||
Read();
|
||||
}
|
||||
|
||||
Ch Peek() const { return *current_; }
|
||||
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
BasicIStreamWrapper();
|
||||
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
||||
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
||||
|
||||
void Read() {
|
||||
if (current_ < bufferLast_)
|
||||
++current_;
|
||||
else if (!eof_) {
|
||||
count_ += readCount_;
|
||||
readCount_ = bufferSize_;
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
|
||||
readCount_ = static_cast<size_t>(stream_.gcount());
|
||||
*(bufferLast_ = buffer_ + readCount_) = '\0';
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StreamType &stream_;
|
||||
Ch peekBuffer_[4], *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
||||
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ISTREAMWRAPPER_H_
|
||||
70
util/xpack/rapidjson/memorybuffer.h
Executable file
70
util/xpack/rapidjson/memorybuffer.h
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_MEMORYBUFFER_H_
|
||||
#define RAPIDJSON_MEMORYBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output byte stream.
|
||||
/*!
|
||||
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
|
||||
|
||||
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
|
||||
|
||||
Differences between MemoryBuffer and StringBuffer:
|
||||
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
|
||||
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
|
||||
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Allocator = CrtAllocator>
|
||||
struct GenericMemoryBuffer {
|
||||
typedef char Ch; // byte
|
||||
|
||||
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() { stack_.ShrinkToFit(); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||
|
||||
const Ch* GetBuffer() const {
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
typedef GenericMemoryBuffer<> MemoryBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
|
||||
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||
71
util/xpack/rapidjson/memorystream.h
Executable file
71
util/xpack/rapidjson/memorystream.h
Executable file
|
|
@ -0,0 +1,71 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_MEMORYSTREAM_H_
|
||||
#define RAPIDJSON_MEMORYSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory input byte stream.
|
||||
/*!
|
||||
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
|
||||
|
||||
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
|
||||
|
||||
Differences between MemoryStream and StringStream:
|
||||
1. StringStream has encoding but MemoryStream is a byte stream.
|
||||
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
|
||||
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
|
||||
\note implements Stream concept
|
||||
*/
|
||||
struct MemoryStream {
|
||||
typedef char Ch; // byte
|
||||
|
||||
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
|
||||
|
||||
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
|
||||
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
// For encoding detection only.
|
||||
const Ch* Peek4() const {
|
||||
return Tell() + 4 <= size_ ? src_ : 0;
|
||||
}
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* begin_; //!< Original head of the string.
|
||||
const Ch* end_; //!< End of stream.
|
||||
size_t size_; //!< Size of the stream.
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
||||
316
util/xpack/rapidjson/msinttypes/inttypes.h
Executable file
316
util/xpack/rapidjson/msinttypes/inttypes.h
Executable file
|
|
@ -0,0 +1,316 @@
|
|||
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The above software in this distribution may have been modified by
|
||||
// THL A29 Limited ("Tencent Modifications").
|
||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_ // [
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
// miloyip: VC supports inttypes.h since VC2013
|
||||
#if _MSC_VER >= 1800
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
|
||||
// 7.8 Format conversion of integer types
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
// 7.8.1 Macros for format specifiers
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||
|
||||
// The fprintf macros for signed integers are:
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIdLEAST16 "hd"
|
||||
#define PRIiLEAST16 "hi"
|
||||
#define PRIdFAST16 "hd"
|
||||
#define PRIiFAST16 "hi"
|
||||
|
||||
#define PRId32 "I32d"
|
||||
#define PRIi32 "I32i"
|
||||
#define PRIdLEAST32 "I32d"
|
||||
#define PRIiLEAST32 "I32i"
|
||||
#define PRIdFAST32 "I32d"
|
||||
#define PRIiFAST32 "I32i"
|
||||
|
||||
#define PRId64 "I64d"
|
||||
#define PRIi64 "I64i"
|
||||
#define PRIdLEAST64 "I64d"
|
||||
#define PRIiLEAST64 "I64i"
|
||||
#define PRIdFAST64 "I64d"
|
||||
#define PRIiFAST64 "I64i"
|
||||
|
||||
#define PRIdMAX "I64d"
|
||||
#define PRIiMAX "I64i"
|
||||
|
||||
#define PRIdPTR "Id"
|
||||
#define PRIiPTR "Ii"
|
||||
|
||||
// The fprintf macros for unsigned integers are:
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRIoLEAST16 "ho"
|
||||
#define PRIuLEAST16 "hu"
|
||||
#define PRIxLEAST16 "hx"
|
||||
#define PRIXLEAST16 "hX"
|
||||
#define PRIoFAST16 "ho"
|
||||
#define PRIuFAST16 "hu"
|
||||
#define PRIxFAST16 "hx"
|
||||
#define PRIXFAST16 "hX"
|
||||
|
||||
#define PRIo32 "I32o"
|
||||
#define PRIu32 "I32u"
|
||||
#define PRIx32 "I32x"
|
||||
#define PRIX32 "I32X"
|
||||
#define PRIoLEAST32 "I32o"
|
||||
#define PRIuLEAST32 "I32u"
|
||||
#define PRIxLEAST32 "I32x"
|
||||
#define PRIXLEAST32 "I32X"
|
||||
#define PRIoFAST32 "I32o"
|
||||
#define PRIuFAST32 "I32u"
|
||||
#define PRIxFAST32 "I32x"
|
||||
#define PRIXFAST32 "I32X"
|
||||
|
||||
#define PRIo64 "I64o"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIx64 "I64x"
|
||||
#define PRIX64 "I64X"
|
||||
#define PRIoLEAST64 "I64o"
|
||||
#define PRIuLEAST64 "I64u"
|
||||
#define PRIxLEAST64 "I64x"
|
||||
#define PRIXLEAST64 "I64X"
|
||||
#define PRIoFAST64 "I64o"
|
||||
#define PRIuFAST64 "I64u"
|
||||
#define PRIxFAST64 "I64x"
|
||||
#define PRIXFAST64 "I64X"
|
||||
|
||||
#define PRIoMAX "I64o"
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRIxMAX "I64x"
|
||||
#define PRIXMAX "I64X"
|
||||
|
||||
#define PRIoPTR "Io"
|
||||
#define PRIuPTR "Iu"
|
||||
#define PRIxPTR "Ix"
|
||||
#define PRIXPTR "IX"
|
||||
|
||||
// The fscanf macros for signed integers are:
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNdLEAST8 "d"
|
||||
#define SCNiLEAST8 "i"
|
||||
#define SCNdFAST8 "d"
|
||||
#define SCNiFAST8 "i"
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNdLEAST16 "hd"
|
||||
#define SCNiLEAST16 "hi"
|
||||
#define SCNdFAST16 "hd"
|
||||
#define SCNiFAST16 "hi"
|
||||
|
||||
#define SCNd32 "ld"
|
||||
#define SCNi32 "li"
|
||||
#define SCNdLEAST32 "ld"
|
||||
#define SCNiLEAST32 "li"
|
||||
#define SCNdFAST32 "ld"
|
||||
#define SCNiFAST32 "li"
|
||||
|
||||
#define SCNd64 "I64d"
|
||||
#define SCNi64 "I64i"
|
||||
#define SCNdLEAST64 "I64d"
|
||||
#define SCNiLEAST64 "I64i"
|
||||
#define SCNdFAST64 "I64d"
|
||||
#define SCNiFAST64 "I64i"
|
||||
|
||||
#define SCNdMAX "I64d"
|
||||
#define SCNiMAX "I64i"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNdPTR "I64d"
|
||||
# define SCNiPTR "I64i"
|
||||
#else // _WIN64 ][
|
||||
# define SCNdPTR "ld"
|
||||
# define SCNiPTR "li"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// The fscanf macros for unsigned integers are:
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
#define SCNoLEAST8 "o"
|
||||
#define SCNuLEAST8 "u"
|
||||
#define SCNxLEAST8 "x"
|
||||
#define SCNXLEAST8 "X"
|
||||
#define SCNoFAST8 "o"
|
||||
#define SCNuFAST8 "u"
|
||||
#define SCNxFAST8 "x"
|
||||
#define SCNXFAST8 "X"
|
||||
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
#define SCNoLEAST16 "ho"
|
||||
#define SCNuLEAST16 "hu"
|
||||
#define SCNxLEAST16 "hx"
|
||||
#define SCNXLEAST16 "hX"
|
||||
#define SCNoFAST16 "ho"
|
||||
#define SCNuFAST16 "hu"
|
||||
#define SCNxFAST16 "hx"
|
||||
#define SCNXFAST16 "hX"
|
||||
|
||||
#define SCNo32 "lo"
|
||||
#define SCNu32 "lu"
|
||||
#define SCNx32 "lx"
|
||||
#define SCNX32 "lX"
|
||||
#define SCNoLEAST32 "lo"
|
||||
#define SCNuLEAST32 "lu"
|
||||
#define SCNxLEAST32 "lx"
|
||||
#define SCNXLEAST32 "lX"
|
||||
#define SCNoFAST32 "lo"
|
||||
#define SCNuFAST32 "lu"
|
||||
#define SCNxFAST32 "lx"
|
||||
#define SCNXFAST32 "lX"
|
||||
|
||||
#define SCNo64 "I64o"
|
||||
#define SCNu64 "I64u"
|
||||
#define SCNx64 "I64x"
|
||||
#define SCNX64 "I64X"
|
||||
#define SCNoLEAST64 "I64o"
|
||||
#define SCNuLEAST64 "I64u"
|
||||
#define SCNxLEAST64 "I64x"
|
||||
#define SCNXLEAST64 "I64X"
|
||||
#define SCNoFAST64 "I64o"
|
||||
#define SCNuFAST64 "I64u"
|
||||
#define SCNxFAST64 "I64x"
|
||||
#define SCNXFAST64 "I64X"
|
||||
|
||||
#define SCNoMAX "I64o"
|
||||
#define SCNuMAX "I64u"
|
||||
#define SCNxMAX "I64x"
|
||||
#define SCNXMAX "I64X"
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define SCNoPTR "I64o"
|
||||
# define SCNuPTR "I64u"
|
||||
# define SCNxPTR "I64x"
|
||||
# define SCNXPTR "I64X"
|
||||
#else // _WIN64 ][
|
||||
# define SCNoPTR "lo"
|
||||
# define SCNuPTR "lu"
|
||||
# define SCNxPTR "lx"
|
||||
# define SCNXPTR "lX"
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#endif // __STDC_FORMAT_MACROS ]
|
||||
|
||||
// 7.8.2 Functions for greatest-width integer types
|
||||
|
||||
// 7.8.2.1 The imaxabs function
|
||||
#define imaxabs _abs64
|
||||
|
||||
// 7.8.2.2 The imaxdiv function
|
||||
|
||||
// This is modified version of div() function from Microsoft's div.c found
|
||||
// in %MSVC.NET%\crt\src\div.c
|
||||
#ifdef STATIC_IMAXDIV // [
|
||||
static
|
||||
#else // STATIC_IMAXDIV ][
|
||||
_inline
|
||||
#endif // STATIC_IMAXDIV ]
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||
{
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
// did division wrong; must fix up
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
|
||||
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
|
||||
#endif // _MSC_VER >= 1800
|
||||
|
||||
#endif // _MSC_INTTYPES_H_ ]
|
||||
300
util/xpack/rapidjson/msinttypes/stdint.h
Executable file
300
util/xpack/rapidjson/msinttypes/stdint.h
Executable file
|
|
@ -0,0 +1,300 @@
|
|||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the product nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The above software in this distribution may have been modified by
|
||||
// THL A29 Limited ("Tencent Modifications").
|
||||
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
|
||||
#if _MSC_VER >= 1600 // [
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
#undef INT8_C
|
||||
#undef INT16_C
|
||||
#undef INT32_C
|
||||
#undef INT64_C
|
||||
#undef UINT8_C
|
||||
#undef UINT16_C
|
||||
#undef UINT32_C
|
||||
#undef UINT64_C
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#else // ] _MSC_VER >= 1700 [
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler would give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#endif // _MSC_VER >= 1600 ]
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
81
util/xpack/rapidjson/ostreamwrapper.h
Executable file
81
util/xpack/rapidjson/ostreamwrapper.h
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
#define RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <iosfwd>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
|
||||
/*!
|
||||
The classes can be wrapped including but not limited to:
|
||||
|
||||
- \c std::ostringstream
|
||||
- \c std::stringstream
|
||||
- \c std::wpstringstream
|
||||
- \c std::wstringstream
|
||||
- \c std::ifstream
|
||||
- \c std::fstream
|
||||
- \c std::wofstream
|
||||
- \c std::wfstream
|
||||
|
||||
\tparam StreamType Class derived from \c std::basic_ostream.
|
||||
*/
|
||||
|
||||
template <typename StreamType>
|
||||
class BasicOStreamWrapper {
|
||||
public:
|
||||
typedef typename StreamType::char_type Ch;
|
||||
BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
|
||||
|
||||
void Put(Ch c) {
|
||||
stream_.put(c);
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
stream_.flush();
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
BasicOStreamWrapper(const BasicOStreamWrapper&);
|
||||
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
|
||||
|
||||
StreamType& stream_;
|
||||
};
|
||||
|
||||
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
|
||||
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_OSTREAMWRAPPER_H_
|
||||
1414
util/xpack/rapidjson/pointer.h
Executable file
1414
util/xpack/rapidjson/pointer.h
Executable file
File diff suppressed because it is too large
Load diff
277
util/xpack/rapidjson/prettywriter.h
Executable file
277
util/xpack/rapidjson/prettywriter.h
Executable file
|
|
@ -0,0 +1,277 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Combination of PrettyWriter format flags.
|
||||
/*! \see PrettyWriter::SetFormatOptions
|
||||
*/
|
||||
enum PrettyFormatOptions {
|
||||
kFormatDefault = 0, //!< Default pretty formatting.
|
||||
kFormatSingleLineArray = 1 //!< Format arrays on a single line.
|
||||
};
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam OutputStream Type of output os.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
|
||||
public:
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
|
||||
typedef typename Base::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
|
||||
|
||||
|
||||
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
PrettyWriter(PrettyWriter&& rhs) :
|
||||
Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
|
||||
#endif
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Set pretty writer formatting options.
|
||||
/*! \param options Formatting options.
|
||||
*/
|
||||
PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
|
||||
formatOptions_ = options;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! @name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); }
|
||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
|
||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
|
||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
|
||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
|
||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); }
|
||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
|
||||
|
||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||
RAPIDJSON_ASSERT(str != 0);
|
||||
(void)copy;
|
||||
PrettyPrefix(kNumberType);
|
||||
return Base::EndValue(Base::WriteString(str, length));
|
||||
}
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
RAPIDJSON_ASSERT(str != 0);
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::EndValue(Base::WriteString(str, length));
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& str) {
|
||||
return String(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool Key(const std::basic_string<Ch>& str) {
|
||||
return Key(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
|
||||
RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
|
||||
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
bool ret = Base::EndValue(Base::WriteEndObject());
|
||||
(void)ret;
|
||||
RAPIDJSON_ASSERT(ret == true);
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||
return Base::WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
bool ret = Base::EndValue(Base::WriteEndArray());
|
||||
(void)ret;
|
||||
RAPIDJSON_ASSERT(ret == true);
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
//! Write a raw JSON value.
|
||||
/*!
|
||||
For user to write a stringified JSON as a value.
|
||||
|
||||
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||
\param length Length of the json.
|
||||
\param type Type of the root of json.
|
||||
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
|
||||
*/
|
||||
bool RawValue(const Ch* json, size_t length, Type type) {
|
||||
RAPIDJSON_ASSERT(json != 0);
|
||||
PrettyPrefix(type);
|
||||
return Base::EndValue(Base::WriteRawValue(json, length));
|
||||
}
|
||||
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||
if (formatOptions_ & kFormatSingleLineArray)
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
|
||||
if (!(formatOptions_ & kFormatSingleLineArray)) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::os_->Put(',');
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::os_->Put(':');
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||
Base::hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
PrettyFormatOptions formatOptions_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
656
util/xpack/rapidjson/rapidjson.h
Executable file
656
util/xpack/rapidjson/rapidjson.h
Executable file
|
|
@ -0,0 +1,656 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
/*!\file rapidjson.h
|
||||
\brief common definitions and configuration
|
||||
|
||||
\see RAPIDJSON_CONFIG
|
||||
*/
|
||||
|
||||
/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
|
||||
\brief Configuration macros for library features
|
||||
|
||||
Some RapidJSON features are configurable to adapt the library to a wide
|
||||
variety of platforms, environments and usage scenarios. Most of the
|
||||
features can be configured in terms of overridden or predefined
|
||||
preprocessor macros at compile-time.
|
||||
|
||||
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
|
||||
|
||||
\note These macros should be given on the compiler command-line
|
||||
(where applicable) to avoid inconsistent values when compiling
|
||||
different translation units of a single application.
|
||||
*/
|
||||
|
||||
#include <cstdlib> // malloc(), realloc(), free(), size_t
|
||||
#include <cstring> // memset(), memcpy(), memmove(), memcmp()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_VERSION_STRING
|
||||
//
|
||||
// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
|
||||
//
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
// token stringification
|
||||
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
|
||||
#define RAPIDJSON_DO_STRINGIFY(x) #x
|
||||
|
||||
// token concatenation
|
||||
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
|
||||
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
|
||||
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
|
||||
//!@endcond
|
||||
|
||||
/*! \def RAPIDJSON_MAJOR_VERSION
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Major version of RapidJSON in integer.
|
||||
*/
|
||||
/*! \def RAPIDJSON_MINOR_VERSION
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Minor version of RapidJSON in integer.
|
||||
*/
|
||||
/*! \def RAPIDJSON_PATCH_VERSION
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Patch version of RapidJSON in integer.
|
||||
*/
|
||||
/*! \def RAPIDJSON_VERSION_STRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
|
||||
*/
|
||||
#define RAPIDJSON_MAJOR_VERSION 1
|
||||
#define RAPIDJSON_MINOR_VERSION 1
|
||||
#define RAPIDJSON_PATCH_VERSION 0
|
||||
#define RAPIDJSON_VERSION_STRING \
|
||||
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NAMESPACE_(BEGIN|END)
|
||||
/*! \def RAPIDJSON_NAMESPACE
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief provide custom rapidjson namespace
|
||||
|
||||
In order to avoid symbol clashes and/or "One Definition Rule" errors
|
||||
between multiple inclusions of (different versions of) RapidJSON in
|
||||
a single binary, users can customize the name of the main RapidJSON
|
||||
namespace.
|
||||
|
||||
In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
|
||||
to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
|
||||
levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
|
||||
RAPIDJSON_NAMESPACE_END need to be defined as well:
|
||||
|
||||
\code
|
||||
// in some .cpp file
|
||||
#define RAPIDJSON_NAMESPACE my::rapidjson
|
||||
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
|
||||
#define RAPIDJSON_NAMESPACE_END } }
|
||||
#include "rapidjson/..."
|
||||
\endcode
|
||||
|
||||
\see rapidjson
|
||||
*/
|
||||
/*! \def RAPIDJSON_NAMESPACE_BEGIN
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief provide custom rapidjson namespace (opening expression)
|
||||
\see RAPIDJSON_NAMESPACE
|
||||
*/
|
||||
/*! \def RAPIDJSON_NAMESPACE_END
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief provide custom rapidjson namespace (closing expression)
|
||||
\see RAPIDJSON_NAMESPACE
|
||||
*/
|
||||
#ifndef RAPIDJSON_NAMESPACE
|
||||
#define RAPIDJSON_NAMESPACE rapidjson
|
||||
#endif
|
||||
#ifndef RAPIDJSON_NAMESPACE_BEGIN
|
||||
#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
|
||||
#endif
|
||||
#ifndef RAPIDJSON_NAMESPACE_END
|
||||
#define RAPIDJSON_NAMESPACE_END }
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||
#else
|
||||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||
#endif
|
||||
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable RapidJSON support for \c std::string
|
||||
|
||||
By defining this preprocessor symbol to \c 1, several convenience functions for using
|
||||
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
||||
for construction and comparison.
|
||||
|
||||
\hideinitializer
|
||||
*/
|
||||
#endif // !defined(RAPIDJSON_HAS_STDSTRING)
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
#include <string>
|
||||
#endif // RAPIDJSON_HAS_STDSTRING
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
/*! \def RAPIDJSON_NO_INT64DEFINE
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Use external 64-bit integer types.
|
||||
|
||||
RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
|
||||
to be available at global scope.
|
||||
|
||||
If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
|
||||
prevent RapidJSON from defining its own types.
|
||||
*/
|
||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
|
||||
#include "msinttypes/stdint.h"
|
||||
#include "msinttypes/inttypes.h"
|
||||
#else
|
||||
// Other compilers should have this.
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
//!@endcond
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_NO_INT64DEFINE
|
||||
#endif
|
||||
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_FORCEINLINE
|
||||
|
||||
#ifndef RAPIDJSON_FORCEINLINE
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#if defined(_MSC_VER) && defined(NDEBUG)
|
||||
#define RAPIDJSON_FORCEINLINE __forceinline
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
|
||||
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
|
||||
#else
|
||||
#define RAPIDJSON_FORCEINLINE
|
||||
#endif
|
||||
//!@endcond
|
||||
#endif // RAPIDJSON_FORCEINLINE
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ENDIAN
|
||||
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||
|
||||
//! Endianness of the machine.
|
||||
/*!
|
||||
\def RAPIDJSON_ENDIAN
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
|
||||
GCC 4.6 provided macro for detecting endianness of the target machine. But other
|
||||
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
|
||||
\ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
|
||||
|
||||
Default detection implemented with reference to
|
||||
\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
|
||||
\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
|
||||
*/
|
||||
#ifndef RAPIDJSON_ENDIAN
|
||||
// Detect with GCC 4.6's macro
|
||||
# ifdef __BYTE_ORDER__
|
||||
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __BYTE_ORDER__
|
||||
// Detect with GLIBC's endian.h
|
||||
# elif defined(__GLIBC__)
|
||||
# include <endian.h>
|
||||
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __GLIBC__
|
||||
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
|
||||
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
// Detect with architecture macros
|
||||
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||
# define RAPIDJSON_ENDIAN
|
||||
# else
|
||||
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif
|
||||
#endif // RAPIDJSON_ENDIAN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_64BIT
|
||||
|
||||
//! Whether using 64-bit architecture
|
||||
#ifndef RAPIDJSON_64BIT
|
||||
#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
|
||||
#define RAPIDJSON_64BIT 1
|
||||
#else
|
||||
#define RAPIDJSON_64BIT 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_64BIT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ALIGN
|
||||
|
||||
//! Data alignment of the machine.
|
||||
/*! \ingroup RAPIDJSON_CONFIG
|
||||
\param x pointer to align
|
||||
|
||||
Some machines require strict data alignment. The default is 8 bytes.
|
||||
User can customize by defining the RAPIDJSON_ALIGN function macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ALIGN
|
||||
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_UINT64_C2
|
||||
|
||||
//! Construct a 64-bit literal by a pair of 32-bit integer.
|
||||
/*!
|
||||
64-bit literal with or without ULL suffix is prone to compiler warnings.
|
||||
UINT64_C() is C macro which cause compilation problems.
|
||||
Use this macro to define 64-bit constants by a pair of 32-bit integer.
|
||||
*/
|
||||
#ifndef RAPIDJSON_UINT64_C2
|
||||
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
|
||||
//! Use only lower 48-bit address for some pointers.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
|
||||
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
|
||||
The higher 16-bit can be used for storing other data.
|
||||
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
|
||||
*/
|
||||
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
||||
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
|
||||
#else
|
||||
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||
|
||||
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
|
||||
#if RAPIDJSON_64BIT != 1
|
||||
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
|
||||
#endif
|
||||
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
|
||||
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
|
||||
#else
|
||||
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
|
||||
#define RAPIDJSON_GETPOINTER(type, p) (p)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD
|
||||
|
||||
/*! \def RAPIDJSON_SIMD
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief Enable SSE2/SSE4.2/Neon optimization.
|
||||
|
||||
RapidJSON supports optimized implementations for some parsing operations
|
||||
based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel
|
||||
or ARM compatible processors.
|
||||
|
||||
To enable these optimizations, three different symbols can be defined;
|
||||
\code
|
||||
// Enable SSE2 optimization.
|
||||
#define RAPIDJSON_SSE2
|
||||
|
||||
// Enable SSE4.2 optimization.
|
||||
#define RAPIDJSON_SSE42
|
||||
\endcode
|
||||
|
||||
// Enable ARM Neon optimization.
|
||||
#define RAPIDJSON_NEON
|
||||
\endcode
|
||||
|
||||
\c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.
|
||||
|
||||
If any of these symbols is defined, RapidJSON defines the macro
|
||||
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
|
||||
*/
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
|
||||
|| defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||
#define RAPIDJSON_SIMD
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
|
||||
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief User-provided \c SizeType definition.
|
||||
|
||||
In order to avoid using 32-bit size types for indexing strings and arrays,
|
||||
define this preprocessor symbol and provide the type rapidjson::SizeType
|
||||
before including RapidJSON:
|
||||
\code
|
||||
#define RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
namespace rapidjson { typedef ::std::size_t SizeType; }
|
||||
#include "rapidjson/..."
|
||||
\endcode
|
||||
|
||||
\see rapidjson::SizeType
|
||||
*/
|
||||
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||
#define RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
#endif
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
//! Size type (for string lengths, array sizes, etc.)
|
||||
/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
|
||||
instead of using \c size_t. Users may override the SizeType by defining
|
||||
\ref RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||
*/
|
||||
typedef unsigned SizeType;
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
#endif
|
||||
|
||||
// always import std::size_t to rapidjson namespace
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
using std::size_t;
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ASSERT
|
||||
|
||||
//! Assertion.
|
||||
/*! \ingroup RAPIDJSON_CONFIG
|
||||
By default, rapidjson uses C \c assert() for internal assertions.
|
||||
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||
|
||||
\note Parsing errors are handled and can be customized by the
|
||||
\ref RAPIDJSON_ERRORS APIs.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_STATIC_ASSERT
|
||||
|
||||
// Prefer C++11 static_assert, if available
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
|
||||
#define RAPIDJSON_STATIC_ASSERT(x) \
|
||||
static_assert(x, RAPIDJSON_STRINGIFY(x))
|
||||
#endif // C++11
|
||||
#endif // RAPIDJSON_STATIC_ASSERT
|
||||
|
||||
// Adopt C++03 implementation from boost
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
#ifndef __clang__
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#endif
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||
template <size_t x> struct StaticAssertTest {};
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
||||
#else
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
#ifndef __clang__
|
||||
//!@endcond
|
||||
#endif
|
||||
|
||||
/*! \def RAPIDJSON_STATIC_ASSERT
|
||||
\brief (Internal) macro to check for conditions at compile-time
|
||||
\param x compile-time condition
|
||||
\hideinitializer
|
||||
*/
|
||||
#define RAPIDJSON_STATIC_ASSERT(x) \
|
||||
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
|
||||
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
|
||||
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif // RAPIDJSON_STATIC_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
|
||||
|
||||
//! Compiler branching hint for expression with high probability to be true.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\param x Boolean expression likely to be true.
|
||||
*/
|
||||
#ifndef RAPIDJSON_LIKELY
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#else
|
||||
#define RAPIDJSON_LIKELY(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//! Compiler branching hint for expression with low probability to be true.
|
||||
/*!
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\param x Boolean expression unlikely to be true.
|
||||
*/
|
||||
#ifndef RAPIDJSON_UNLIKELY
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define RAPIDJSON_UNLIKELY(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
|
||||
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
|
||||
#define RAPIDJSON_MULTILINEMACRO_END \
|
||||
} while((void)0, 0)
|
||||
|
||||
// adopted from Boost
|
||||
#define RAPIDJSON_VERSION_CODE(x,y,z) \
|
||||
(((x)*100000) + ((y)*100) + (z))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define RAPIDJSON_GNUC \
|
||||
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
|
||||
|
||||
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
|
||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
|
||||
#define RAPIDJSON_DIAG_OFF(x) \
|
||||
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
|
||||
|
||||
// push/pop support in Clang and GCC>=4.6
|
||||
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
|
||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
#else // GCC >= 4.2, < 4.6
|
||||
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
// pragma (MSVC specific)
|
||||
#define RAPIDJSON_PRAGMA(x) __pragma(x)
|
||||
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
|
||||
|
||||
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
|
||||
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||
|
||||
#else
|
||||
|
||||
#define RAPIDJSON_DIAG_OFF(x) /* ignored */
|
||||
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||
|
||||
#endif // RAPIDJSON_DIAG_*
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// C++11 features
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#if defined(__clang__)
|
||||
#if __has_feature(cxx_rvalue_references) && \
|
||||
(defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||
#endif
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1600) || \
|
||||
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#if defined(__clang__)
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1900) || \
|
||||
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||
#endif
|
||||
#endif
|
||||
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#define RAPIDJSON_NOEXCEPT noexcept
|
||||
#else
|
||||
#define RAPIDJSON_NOEXCEPT /* noexcept */
|
||||
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
|
||||
// no automatic detection, yet
|
||||
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1700)
|
||||
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||
#if defined(__clang__)
|
||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
|
||||
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1700) || \
|
||||
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
|
||||
#else
|
||||
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
|
||||
#endif
|
||||
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||
|
||||
//!@endcond
|
||||
|
||||
//! Assertion (in non-throwing contexts).
|
||||
/*! \ingroup RAPIDJSON_CONFIG
|
||||
Some functions provide a \c noexcept guarantee, if the compiler supports it.
|
||||
In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to
|
||||
throw an exception. This macro adds a separate customization point for
|
||||
such cases.
|
||||
|
||||
Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is
|
||||
supported, and to \ref RAPIDJSON_ASSERT otherwise.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NOEXCEPT_ASSERT
|
||||
|
||||
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
|
||||
#ifdef RAPIDJSON_ASSERT_THROWS
|
||||
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
|
||||
#else
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
|
||||
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||
#else
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
|
||||
#endif // RAPIDJSON_ASSERT_THROWS
|
||||
#endif // RAPIDJSON_NOEXCEPT_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// new/delete
|
||||
|
||||
#ifndef RAPIDJSON_NEW
|
||||
///! customization point for global \c new
|
||||
#define RAPIDJSON_NEW(TypeName) new TypeName
|
||||
#endif
|
||||
#ifndef RAPIDJSON_DELETE
|
||||
///! customization point for global \c delete
|
||||
#define RAPIDJSON_DELETE(x) delete x
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Type
|
||||
|
||||
/*! \namespace rapidjson
|
||||
\brief main RapidJSON namespace
|
||||
\see RAPIDJSON_NAMESPACE
|
||||
*/
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Type of JSON value
|
||||
enum Type {
|
||||
kNullType = 0, //!< null
|
||||
kFalseType = 1, //!< false
|
||||
kTrueType = 2, //!< true
|
||||
kObjectType = 3, //!< object
|
||||
kArrayType = 4, //!< array
|
||||
kStringType = 5, //!< string
|
||||
kNumberType = 6 //!< number
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
2230
util/xpack/rapidjson/reader.h
Executable file
2230
util/xpack/rapidjson/reader.h
Executable file
File diff suppressed because it is too large
Load diff
2496
util/xpack/rapidjson/schema.h
Executable file
2496
util/xpack/rapidjson/schema.h
Executable file
File diff suppressed because it is too large
Load diff
223
util/xpack/rapidjson/stream.h
Executable file
223
util/xpack/rapidjson/stream.h
Executable file
|
|
@ -0,0 +1,223 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifndef RAPIDJSON_STREAM_H_
|
||||
#define RAPIDJSON_STREAM_H_
|
||||
|
||||
#include "encodings.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stream
|
||||
|
||||
/*! \class rapidjson::Stream
|
||||
\brief Concept for reading and writing characters.
|
||||
|
||||
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
|
||||
|
||||
For write-only stream, only need to implement Put() and Flush().
|
||||
|
||||
\code
|
||||
concept Stream {
|
||||
typename Ch; //!< Character type of the stream.
|
||||
|
||||
//! Read the current character from stream without moving the read cursor.
|
||||
Ch Peek() const;
|
||||
|
||||
//! Read the current character from stream and moving the read cursor to next character.
|
||||
Ch Take();
|
||||
|
||||
//! Get the current read cursor.
|
||||
//! \return Number of characters read from start.
|
||||
size_t Tell();
|
||||
|
||||
//! Begin writing operation at the current read pointer.
|
||||
//! \return The begin writer pointer.
|
||||
Ch* PutBegin();
|
||||
|
||||
//! Write a character.
|
||||
void Put(Ch c);
|
||||
|
||||
//! Flush the buffer.
|
||||
void Flush();
|
||||
|
||||
//! End the writing operation.
|
||||
//! \param begin The begin write pointer returned by PutBegin().
|
||||
//! \return Number of characters written.
|
||||
size_t PutEnd(Ch* begin);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
|
||||
//! Provides additional information for stream.
|
||||
/*!
|
||||
By using traits pattern, this type provides a default configuration for stream.
|
||||
For custom stream, this type can be specialized for other configuration.
|
||||
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||
*/
|
||||
template<typename Stream>
|
||||
struct StreamTraits {
|
||||
//! Whether to make local copy of stream for optimization during parsing.
|
||||
/*!
|
||||
By default, for safety, streams do not use local copy optimization.
|
||||
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||
*/
|
||||
enum { copyOptimization = 0 };
|
||||
};
|
||||
|
||||
//! Reserve n characters for writing to a stream.
|
||||
template<typename Stream>
|
||||
inline void PutReserve(Stream& stream, size_t count) {
|
||||
(void)stream;
|
||||
(void)count;
|
||||
}
|
||||
|
||||
//! Write character to a stream, presuming buffer is reserved.
|
||||
template<typename Stream>
|
||||
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
PutReserve(stream, n);
|
||||
for (size_t i = 0; i < n; i++)
|
||||
PutUnsafe(stream, c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericStreamWrapper
|
||||
|
||||
//! A Stream Wrapper
|
||||
/*! \tThis string stream is a wrapper for any stream by just forwarding any
|
||||
\treceived message to the origin stream.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
template <typename InputStream, typename Encoding = UTF8<> >
|
||||
class GenericStreamWrapper {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
GenericStreamWrapper(InputStream& is): is_(is) {}
|
||||
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() { return is_.Tell(); }
|
||||
Ch* PutBegin() { return is_.PutBegin(); }
|
||||
void Put(Ch ch) { is_.Put(ch); }
|
||||
void Flush() { is_.Flush(); }
|
||||
size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
|
||||
|
||||
// wrapper for MemoryStream
|
||||
const Ch* Peek4() const { return is_.Peek4(); }
|
||||
|
||||
// wrapper for AutoUTFInputStream
|
||||
UTFType GetType() const { return is_.GetType(); }
|
||||
bool HasBOM() const { return is_.HasBOM(); }
|
||||
|
||||
protected:
|
||||
InputStream& is_;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||
|
||||
Ch Peek() const { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
const Ch* src_; //!< Current read position.
|
||||
const Ch* head_; //!< Original head of the string.
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! String stream with UTF8 encoding.
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
struct GenericInsituStringStream {
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||
|
||||
// Read
|
||||
Ch Peek() { return *src_; }
|
||||
Ch Take() { return *src_++; }
|
||||
size_t Tell() { return static_cast<size_t>(src_ - head_); }
|
||||
|
||||
// Write
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
|
||||
void Flush() {}
|
||||
|
||||
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
|
||||
void Pop(size_t count) { dst_ -= count; }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! Insitu string stream with UTF8 encoding.
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_STREAM_H_
|
||||
121
util/xpack/rapidjson/stringbuffer.h
Executable file
121
util/xpack/rapidjson/stringbuffer.h
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#endif
|
||||
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericStringBuffer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
|
||||
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
|
||||
if (&rhs != this)
|
||||
stack_ = std::move(rhs.stack_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.ShrinkToFit();
|
||||
stack_.template Pop<Ch>(1);
|
||||
}
|
||||
|
||||
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
|
||||
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||
|
||||
const Ch* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
//! Get the size of string in bytes in the string buffer.
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
//! Get the length of string in Ch in the string buffer.
|
||||
size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
GenericStringBuffer(const GenericStringBuffer&);
|
||||
GenericStringBuffer& operator=(const GenericStringBuffer&);
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||
stream.Reserve(count);
|
||||
}
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||
stream.PutUnsafe(c);
|
||||
}
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
709
util/xpack/rapidjson/writer.h
Executable file
709
util/xpack/rapidjson/writer.h
Executable file
|
|
@ -0,0 +1,709 @@
|
|||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_WRITER_H_
|
||||
#define RAPIDJSON_WRITER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/meta.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include "internal/dtoa.h"
|
||||
#include "internal/itoa.h"
|
||||
#include "stringbuffer.h"
|
||||
#include <new> // placement new
|
||||
|
||||
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif
|
||||
#ifdef RAPIDJSON_SSE42
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(RAPIDJSON_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#elif defined(RAPIDJSON_NEON)
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#elif defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WriteFlag
|
||||
|
||||
/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
\ingroup RAPIDJSON_CONFIG
|
||||
\brief User-defined kWriteDefaultFlags definition.
|
||||
|
||||
User can define this as any \c WriteFlag combinations.
|
||||
*/
|
||||
#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
|
||||
#endif
|
||||
|
||||
//! Combination of writeFlags
|
||||
enum WriteFlag {
|
||||
kWriteNoFlags = 0, //!< No flags are set.
|
||||
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
|
||||
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
|
||||
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
};
|
||||
|
||||
//! JSON writer
|
||||
/*! Writer implements the concept Handler.
|
||||
It generates JSON text by events to an output os.
|
||||
|
||||
User may programmatically calls the functions of a writer to generate JSON text.
|
||||
|
||||
On the other side, a writer can also be passed to objects that generates events,
|
||||
|
||||
for example Reader::Parse() and Document::Accept().
|
||||
|
||||
\tparam OutputStream Type of output stream.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||
\note implements Handler concept
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||
class Writer {
|
||||
public:
|
||||
typedef typename SourceEncoding::Ch Ch;
|
||||
|
||||
static const int kDefaultMaxDecimalPlaces = 324;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param stackAllocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
explicit
|
||||
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
|
||||
|
||||
explicit
|
||||
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Writer(Writer&& rhs) :
|
||||
os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
|
||||
rhs.os_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Reset the writer with a new stream.
|
||||
/*!
|
||||
This function reset the writer with a new stream and default settings,
|
||||
in order to make a Writer object reusable for output multiple JSONs.
|
||||
|
||||
\param os New output stream.
|
||||
\code
|
||||
Writer<OutputStream> writer(os1);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
|
||||
writer.Reset(os2);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
\endcode
|
||||
*/
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
hasRoot_ = false;
|
||||
level_stack_.Clear();
|
||||
}
|
||||
|
||||
//! Checks whether the output is a complete JSON.
|
||||
/*!
|
||||
A complete JSON has a complete root object or array.
|
||||
*/
|
||||
bool IsComplete() const {
|
||||
return hasRoot_ && level_stack_.Empty();
|
||||
}
|
||||
|
||||
int GetMaxDecimalPlaces() const {
|
||||
return maxDecimalPlaces_;
|
||||
}
|
||||
|
||||
//! Sets the maximum number of decimal places for double output.
|
||||
/*!
|
||||
This setting truncates the output with specified number of decimal places.
|
||||
|
||||
For example,
|
||||
|
||||
\code
|
||||
writer.SetMaxDecimalPlaces(3);
|
||||
writer.StartArray();
|
||||
writer.Double(0.12345); // "0.123"
|
||||
writer.Double(0.0001); // "0.0"
|
||||
writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
|
||||
writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
|
||||
writer.EndArray();
|
||||
\endcode
|
||||
|
||||
The default setting does not truncate any decimal places. You can restore to this setting by calling
|
||||
\code
|
||||
writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
|
||||
\endcode
|
||||
*/
|
||||
void SetMaxDecimalPlaces(int maxDecimalPlaces) {
|
||||
maxDecimalPlaces_ = maxDecimalPlaces;
|
||||
}
|
||||
|
||||
/*!@name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
|
||||
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
|
||||
bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
|
||||
bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
|
||||
bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
|
||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
|
||||
|
||||
//! Writes the given \c double value to the stream
|
||||
/*!
|
||||
\param d The value to be written.
|
||||
\return Whether it is succeed.
|
||||
*/
|
||||
bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
|
||||
|
||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||
RAPIDJSON_ASSERT(str != 0);
|
||||
(void)copy;
|
||||
Prefix(kNumberType);
|
||||
return EndValue(WriteString(str, length));
|
||||
}
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
RAPIDJSON_ASSERT(str != 0);
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
return EndValue(WriteString(str, length));
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& str) {
|
||||
return String(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
return WriteStartObject();
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool Key(const std::basic_string<Ch>& str)
|
||||
{
|
||||
return Key(str.data(), SizeType(str.size()));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
|
||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
|
||||
RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
|
||||
level_stack_.template Pop<Level>(1);
|
||||
return EndValue(WriteEndObject());
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
Prefix(kArrayType);
|
||||
new (level_stack_.template Push<Level>()) Level(true);
|
||||
return WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType elementCount = 0) {
|
||||
(void)elementCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
return EndValue(WriteEndArray());
|
||||
}
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
|
||||
bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
//! Write a raw JSON value.
|
||||
/*!
|
||||
For user to write a stringified JSON as a value.
|
||||
|
||||
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||
\param length Length of the json.
|
||||
\param type Type of the root of json.
|
||||
*/
|
||||
bool RawValue(const Ch* json, size_t length, Type type) {
|
||||
RAPIDJSON_ASSERT(json != 0);
|
||||
Prefix(type);
|
||||
return EndValue(WriteRawValue(json, length));
|
||||
}
|
||||
|
||||
//! Flush the output stream.
|
||||
/*!
|
||||
Allows the user to flush the output stream immediately.
|
||||
*/
|
||||
void Flush() {
|
||||
os_->Flush();
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
|
||||
size_t valueCount; //!< number of values in this level
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
};
|
||||
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
|
||||
bool WriteNull() {
|
||||
PutReserve(*os_, 4);
|
||||
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
|
||||
}
|
||||
|
||||
bool WriteBool(bool b) {
|
||||
if (b) {
|
||||
PutReserve(*os_, 4);
|
||||
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
|
||||
}
|
||||
else {
|
||||
PutReserve(*os_, 5);
|
||||
PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
char buffer[11];
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
char buffer[21];
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char* end = internal::u64toa(u64, buffer);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDouble(double d) {
|
||||
if (internal::Double(d).IsNanOrInf()) {
|
||||
if (!(writeFlags & kWriteNanAndInfFlag))
|
||||
return false;
|
||||
if (internal::Double(d).IsNan()) {
|
||||
PutReserve(*os_, 3);
|
||||
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||
return true;
|
||||
}
|
||||
if (internal::Double(d).Sign()) {
|
||||
PutReserve(*os_, 9);
|
||||
PutUnsafe(*os_, '-');
|
||||
}
|
||||
else
|
||||
PutReserve(*os_, 8);
|
||||
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
|
||||
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
|
||||
return true;
|
||||
}
|
||||
|
||||
char buffer[25];
|
||||
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
|
||||
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
#undef Z16
|
||||
};
|
||||
|
||||
if (TargetEncoding::supportUnicode)
|
||||
PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
|
||||
else
|
||||
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
|
||||
|
||||
PutUnsafe(*os_, '\"');
|
||||
GenericStringStream<SourceEncoding> is(str);
|
||||
while (ScanWriteUnescapedString(is, length)) {
|
||||
const Ch c = is.Peek();
|
||||
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
|
||||
// Unicode escaping
|
||||
unsigned codepoint;
|
||||
if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
|
||||
return false;
|
||||
PutUnsafe(*os_, '\\');
|
||||
PutUnsafe(*os_, 'u');
|
||||
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
||||
PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
|
||||
// Surrogate pair
|
||||
unsigned s = codepoint - 0x010000;
|
||||
unsigned lead = (s >> 10) + 0xD800;
|
||||
unsigned trail = (s & 0x3FF) + 0xDC00;
|
||||
PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(lead ) & 15]);
|
||||
PutUnsafe(*os_, '\\');
|
||||
PutUnsafe(*os_, 'u');
|
||||
PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
|
||||
PutUnsafe(*os_, hexDigits[(trail ) & 15]);
|
||||
}
|
||||
}
|
||||
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
|
||||
is.Take();
|
||||
PutUnsafe(*os_, '\\');
|
||||
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
|
||||
if (escape[static_cast<unsigned char>(c)] == 'u') {
|
||||
PutUnsafe(*os_, '0');
|
||||
PutUnsafe(*os_, '0');
|
||||
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
|
||||
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
|
||||
}
|
||||
}
|
||||
else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
|
||||
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
|
||||
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||
return false;
|
||||
}
|
||||
PutUnsafe(*os_, '\"');
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
|
||||
bool WriteStartObject() { os_->Put('{'); return true; }
|
||||
bool WriteEndObject() { os_->Put('}'); return true; }
|
||||
bool WriteStartArray() { os_->Put('['); return true; }
|
||||
bool WriteEndArray() { os_->Put(']'); return true; }
|
||||
|
||||
bool WriteRawValue(const Ch* json, size_t length) {
|
||||
PutReserve(*os_, length);
|
||||
GenericStringStream<SourceEncoding> is(json);
|
||||
while (RAPIDJSON_LIKELY(is.Tell() < length)) {
|
||||
RAPIDJSON_ASSERT(is.Peek() != '\0');
|
||||
if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
|
||||
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
|
||||
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Prefix(Type type) {
|
||||
(void)type;
|
||||
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
|
||||
Level* level = level_stack_.template Top<Level>();
|
||||
if (level->valueCount > 0) {
|
||||
if (level->inArray)
|
||||
os_->Put(','); // add comma if it is not the first element in array
|
||||
else // in object
|
||||
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
|
||||
hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush the value if it is the top level one.
|
||||
bool EndValue(bool ret) {
|
||||
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
|
||||
Flush();
|
||||
return ret;
|
||||
}
|
||||
|
||||
OutputStream* os_;
|
||||
internal::Stack<StackAllocator> level_stack_;
|
||||
int maxDecimalPlaces_;
|
||||
bool hasRoot_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Writer(const Writer&);
|
||||
Writer& operator=(const Writer&);
|
||||
};
|
||||
|
||||
// Full specialization for StringStream to prevent memory copying
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteInt(int i) {
|
||||
char *buffer = os_->Push(11);
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
os_->Pop(static_cast<size_t>(11 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
|
||||
char *buffer = os_->Push(10);
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
os_->Pop(static_cast<size_t>(10 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
|
||||
char *buffer = os_->Push(21);
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
os_->Pop(static_cast<size_t>(21 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
|
||||
char *buffer = os_->Push(20);
|
||||
const char* end = internal::u64toa(u, buffer);
|
||||
os_->Pop(static_cast<size_t>(20 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::WriteDouble(double d) {
|
||||
if (internal::Double(d).IsNanOrInf()) {
|
||||
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
|
||||
if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
|
||||
return false;
|
||||
if (internal::Double(d).IsNan()) {
|
||||
PutReserve(*os_, 3);
|
||||
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||
return true;
|
||||
}
|
||||
if (internal::Double(d).Sign()) {
|
||||
PutReserve(*os_, 9);
|
||||
PutUnsafe(*os_, '-');
|
||||
}
|
||||
else
|
||||
PutReserve(*os_, 8);
|
||||
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
|
||||
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
|
||||
return true;
|
||||
}
|
||||
|
||||
char *buffer = os_->Push(25);
|
||||
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
|
||||
os_->Pop(static_cast<size_t>(25 - (end - buffer)));
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
|
||||
if (length < 16)
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
|
||||
if (!RAPIDJSON_LIKELY(is.Tell() < length))
|
||||
return false;
|
||||
|
||||
const char* p = is.src_;
|
||||
const char* end = is.head_ + length;
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
|
||||
if (nextAligned > end)
|
||||
return true;
|
||||
|
||||
while (p != nextAligned)
|
||||
if (*p < 0x20 || *p == '\"' || *p == '\\') {
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
else
|
||||
os_->PutUnsafe(*p++);
|
||||
|
||||
// The rest of string using SIMD
|
||||
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
|
||||
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
|
||||
static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
|
||||
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
|
||||
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||
|
||||
for (; p != endAligned; p += 16) {
|
||||
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
|
||||
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
|
||||
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
|
||||
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||
SizeType len;
|
||||
#ifdef _MSC_VER // Find the index of first escaped
|
||||
unsigned long offset;
|
||||
_BitScanForward(&offset, r);
|
||||
len = offset;
|
||||
#else
|
||||
len = static_cast<SizeType>(__builtin_ffs(r) - 1);
|
||||
#endif
|
||||
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
|
||||
for (size_t i = 0; i < len; i++)
|
||||
q[i] = p[i];
|
||||
|
||||
p += len;
|
||||
break;
|
||||
}
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
|
||||
}
|
||||
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
#elif defined(RAPIDJSON_NEON)
|
||||
template<>
|
||||
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
|
||||
if (length < 16)
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
|
||||
if (!RAPIDJSON_LIKELY(is.Tell() < length))
|
||||
return false;
|
||||
|
||||
const char* p = is.src_;
|
||||
const char* end = is.head_ + length;
|
||||
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
|
||||
if (nextAligned > end)
|
||||
return true;
|
||||
|
||||
while (p != nextAligned)
|
||||
if (*p < 0x20 || *p == '\"' || *p == '\\') {
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
else
|
||||
os_->PutUnsafe(*p++);
|
||||
|
||||
// The rest of string using SIMD
|
||||
const uint8x16_t s0 = vmovq_n_u8('"');
|
||||
const uint8x16_t s1 = vmovq_n_u8('\\');
|
||||
const uint8x16_t s2 = vmovq_n_u8('\b');
|
||||
const uint8x16_t s3 = vmovq_n_u8(32);
|
||||
|
||||
for (; p != endAligned; p += 16) {
|
||||
const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
|
||||
uint8x16_t x = vceqq_u8(s, s0);
|
||||
x = vorrq_u8(x, vceqq_u8(s, s1));
|
||||
x = vorrq_u8(x, vceqq_u8(s, s2));
|
||||
x = vorrq_u8(x, vcltq_u8(s, s3));
|
||||
|
||||
x = vrev64q_u8(x); // Rev in 64
|
||||
uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
||||
uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
||||
|
||||
SizeType len = 0;
|
||||
bool escaped = false;
|
||||
if (low == 0) {
|
||||
if (high != 0) {
|
||||
unsigned lz = (unsigned)__builtin_clzll(high);
|
||||
len = 8 + (lz >> 3);
|
||||
escaped = true;
|
||||
}
|
||||
} else {
|
||||
unsigned lz = (unsigned)__builtin_clzll(low);
|
||||
len = lz >> 3;
|
||||
escaped = true;
|
||||
}
|
||||
if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
|
||||
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
|
||||
for (size_t i = 0; i < len; i++)
|
||||
q[i] = p[i];
|
||||
|
||||
p += len;
|
||||
break;
|
||||
}
|
||||
vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
|
||||
}
|
||||
|
||||
is.src_ = p;
|
||||
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||
}
|
||||
#endif // RAPIDJSON_NEON
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
19
util/xpack/rapidjson_custom.h
Executable file
19
util/xpack/rapidjson_custom.h
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef __X_PACK_RAPIDJSON_CUSTOME_H
|
||||
#define __X_PACK_RAPIDJSON_CUSTOME_H
|
||||
|
||||
#ifndef RAPIDJSON_NOEXCEPT_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <stdexcept>
|
||||
#define RAPIDJSON_ASSERT(x) if(!(x)) throw std::runtime_error(#x)
|
||||
#endif
|
||||
|
||||
#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||
#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
52
util/xpack/rapidxml/license.txt
Executable file
52
util/xpack/rapidxml/license.txt
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
Use of this software is granted under one of the following two licenses,
|
||||
to be chosen freely by the user.
|
||||
|
||||
1. Boost Software License - Version 1.0 - August 17th, 2003
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
2. The MIT License
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
406
util/xpack/rapidxml/manual.html
Executable file
406
util/xpack/rapidxml/manual.html
Executable file
File diff suppressed because one or more lines are too long
2596
util/xpack/rapidxml/rapidxml.hpp
Executable file
2596
util/xpack/rapidxml/rapidxml.hpp
Executable file
File diff suppressed because it is too large
Load diff
174
util/xpack/rapidxml/rapidxml_iterators.hpp
Executable file
174
util/xpack/rapidxml/rapidxml_iterators.hpp
Executable file
|
|
@ -0,0 +1,174 @@
|
|||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Iterator of child nodes of xml_node
|
||||
template<class Ch>
|
||||
class node_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_node<Ch> value_type;
|
||||
typedef typename xml_node<Ch> &reference;
|
||||
typedef typename xml_node<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
node_iterator()
|
||||
: m_node(0)
|
||||
{
|
||||
}
|
||||
|
||||
node_iterator(xml_node<Ch> *node)
|
||||
: m_node(node->first_node())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_node);
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_node);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
node_iterator& operator++()
|
||||
{
|
||||
assert(m_node);
|
||||
m_node = m_node->next_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator++(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
node_iterator& operator--()
|
||||
{
|
||||
assert(m_node && m_node->previous_sibling());
|
||||
m_node = m_node->previous_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator--(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
bool operator !=(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node != rhs.m_node;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_node<Ch> *m_node;
|
||||
|
||||
};
|
||||
|
||||
//! Iterator of child attributes of xml_node
|
||||
template<class Ch>
|
||||
class attribute_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_attribute<Ch> value_type;
|
||||
typedef typename xml_attribute<Ch> &reference;
|
||||
typedef typename xml_attribute<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
attribute_iterator()
|
||||
: m_attribute(0)
|
||||
{
|
||||
}
|
||||
|
||||
attribute_iterator(xml_node<Ch> *node)
|
||||
: m_attribute(node->first_attribute())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return *m_attribute;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return m_attribute;
|
||||
}
|
||||
|
||||
attribute_iterator& operator++()
|
||||
{
|
||||
assert(m_attribute);
|
||||
m_attribute = m_attribute->next_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator++(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
attribute_iterator& operator--()
|
||||
{
|
||||
assert(m_attribute && m_attribute->previous_attribute());
|
||||
m_attribute = m_attribute->previous_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator--(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute == rhs.m_attribute;
|
||||
}
|
||||
|
||||
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute != rhs.m_attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_attribute<Ch> *m_attribute;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
421
util/xpack/rapidxml/rapidxml_print.hpp
Executable file
421
util/xpack/rapidxml/rapidxml_print.hpp
Executable file
|
|
@ -0,0 +1,421 @@
|
|||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
122
util/xpack/rapidxml/rapidxml_utils.hpp
Executable file
122
util/xpack/rapidxml/rapidxml_utils.hpp
Executable file
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
||||
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Represents data loaded from a file
|
||||
template<class Ch = char>
|
||||
class file
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||
//! \param filename Filename to load.
|
||||
file(const char *filename)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Open stream
|
||||
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||
if (!stream)
|
||||
throw runtime_error(string("cannot open file ") + filename);
|
||||
stream.unsetf(ios::skipws);
|
||||
|
||||
// Determine stream size
|
||||
stream.seekg(0, ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
// Load data and add terminating 0
|
||||
m_data.resize(size + 1);
|
||||
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||
//! \param stream Stream to load from
|
||||
file(std::basic_istream<Ch> &stream)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Load data and add terminating 0
|
||||
stream.unsetf(ios::skipws);
|
||||
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||
if (stream.fail() || stream.bad())
|
||||
throw runtime_error("error reading stream");
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
Ch *data()
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
const Ch *data() const
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data size.
|
||||
//! \return Size of file data, in characters.
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Ch> m_data; // File data
|
||||
|
||||
};
|
||||
|
||||
//! Counts children of node. Time complexity is O(n).
|
||||
//! \return Number of children of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_children(xml_node<Ch> *node)
|
||||
{
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
std::size_t count = 0;
|
||||
while (child)
|
||||
{
|
||||
++count;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Counts attributes of node. Time complexity is O(n).
|
||||
//! \return Number of attributes of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||
{
|
||||
xml_attribute<Ch> *attr = node->first_attribute();
|
||||
std::size_t count = 0;
|
||||
while (attr)
|
||||
{
|
||||
++count;
|
||||
attr = attr->next_attribute();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
44
util/xpack/sqlite.h
Executable file
44
util/xpack/sqlite.h
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_SQLITE_H
|
||||
#define __X_PACK_SQLITE_H
|
||||
|
||||
#include "sqlite_decoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class sqlite {
|
||||
public:
|
||||
// convert result of sqlite_get_table to a struct or vector<struct>
|
||||
template <class T>
|
||||
static void decode(const char **result, int rows, int cols, T &val) {
|
||||
SQLiteDecoder de(result, rows, cols);
|
||||
de.decode_top(val, NULL);
|
||||
}
|
||||
|
||||
// select name from test where id = 1; // just want to get name, did not want to use a struct
|
||||
template <class T>
|
||||
static void decode(const char **result, int rows, int cols, const std::string&field, T &val) {
|
||||
SQLiteDecoder de(result, rows, cols);
|
||||
de.decode_column(field.c_str(), val, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
195
util/xpack/sqlite_decoder.h
Executable file
195
util/xpack/sqlite_decoder.h
Executable file
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_SQLITE_DECODER_H
|
||||
#define __X_PACK_SQLITE_DECODER_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <sqlite.h>
|
||||
|
||||
#include "extend.h"
|
||||
#include "traits.h"
|
||||
#include "json.h"
|
||||
|
||||
#include "string.h"
|
||||
#include "time.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class SQLiteDecoder {
|
||||
friend class sqlite;
|
||||
public:
|
||||
template <typename T>
|
||||
bool decode(const char*key, T&val, const Extend *ext) {
|
||||
int idx = find(key);
|
||||
if (idx >= 0) {
|
||||
return this->decode_type(idx, val, ext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const char *Name() const { // mysql and sqlite use db
|
||||
return "db";
|
||||
}
|
||||
|
||||
private:
|
||||
const char **_res;
|
||||
const int _rows;
|
||||
const int _cols;
|
||||
int _offset;
|
||||
std::map<const char*, int, cmp_str> _index;
|
||||
|
||||
SQLiteDecoder(const char**result, int rows, int cols):_res(result), _rows(rows), _cols(cols) {
|
||||
for (int i=0; i<cols; ++i) {
|
||||
_index[_res[i]] = i;
|
||||
}
|
||||
_offset = cols;
|
||||
}
|
||||
|
||||
// decode to struct
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_top(T& val, const Extend *ext) {
|
||||
if (_rows > 0) {
|
||||
val.__x_pack_decode(*this, val, ext);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_top(std::vector<T>& val, const Extend *ext) {
|
||||
for (int i=0; i<_rows; ++i) {
|
||||
val.push_back(T());
|
||||
T& tmp = val.back();
|
||||
tmp.__x_pack_decode(*this, tmp, ext);
|
||||
_offset += _cols;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_top(T& val, const Extend *ext) {
|
||||
if (_rows > 0) {
|
||||
__x_pack_decode_out(*this, val, ext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_top(std::vector<T>& val, const Extend *ext) {
|
||||
for (int i=0; i<_rows; ++i) {
|
||||
val.push_back(T());
|
||||
__x_pack_decode_out(*this, val.back(), ext);
|
||||
_offset += _cols;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// decode special column of first row
|
||||
template <class T>
|
||||
bool decode_column(const char*field, T&val, const Extend *ext) {
|
||||
int idx;
|
||||
if (_rows>0 && (0 <= (idx = find(field)))) {
|
||||
return decode_type(idx, val, ext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// decode special column of rows
|
||||
template <class T>
|
||||
bool decode_column(const char*field, std::vector<T>&val, const Extend *ext) {
|
||||
int idx;
|
||||
if (0 > (idx = find(field))) {
|
||||
return false;
|
||||
}
|
||||
for (int i=0; i<_rows; ++i) {
|
||||
T t;
|
||||
decode_type(idx, t, ext);
|
||||
val.push_back(t);
|
||||
_offset += _cols;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int find(const char*field) const {
|
||||
std::map<const char*, int, cmp_str>::const_iterator it = _index.find(field);
|
||||
if (it != _index.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// std::string
|
||||
bool decode_type(const int idx, std::string &val, const Extend *ext) {
|
||||
const char* s;
|
||||
if (NULL != (s = _res[idx + _offset])) {
|
||||
val = s;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// bool
|
||||
bool decode_type(const int idx, bool &val, const Extend *ext) {
|
||||
int tmp;
|
||||
if (decode_type(idx, tmp, ext)) {
|
||||
val = tmp != 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// integer
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type decode_type(const int idx, T &val, const Extend *ext) {
|
||||
const char* s;
|
||||
if (NULL != (s = _res[idx + _offset])) {
|
||||
val = (T)std::strtoul(s, NULL, 10);
|
||||
} // else val = 0 ???
|
||||
return true;
|
||||
}
|
||||
// float
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type decode_type(const int idx, T &val, const Extend *ext) {
|
||||
const char* s;
|
||||
if (NULL != (s = _res[idx + _offset])) {
|
||||
val = (T)std::strtod(s, NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// class/struct defined XPACK/XPACK_OUT, default use json to parse
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_type(const int idx, T &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
const char* s;
|
||||
if (NULL != (s = _res[idx + _offset])) {
|
||||
return xpack::json::decode(s, val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_type(const int idx, T &val, const Extend *ext) {
|
||||
(void)ext;
|
||||
const char* s;
|
||||
if (NULL != (s = _res[idx + _offset])) {
|
||||
return xpack::json::decode(s, val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
111
util/xpack/traits.h
Executable file
111
util/xpack/traits.h
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_TRAITS_H
|
||||
#define __X_PACK_TRAITS_H
|
||||
|
||||
#if __GXX_EXPERIMENTAL_CXX0X__ || _MSC_VER>=1700
|
||||
#define X_PACK_SUPPORT_CXX0X 1
|
||||
#endif
|
||||
|
||||
namespace xpack {
|
||||
|
||||
// implement std::enable_if
|
||||
template<bool B, class T = void>
|
||||
struct x_enable_if {};
|
||||
template <class T>
|
||||
struct x_enable_if<true, T> { typedef T type; };
|
||||
|
||||
// mark XPACK_OUT
|
||||
template <class T>
|
||||
struct is_xpack_out{static bool const value = false;};
|
||||
|
||||
template <class T>
|
||||
struct is_xpack_xtype {static bool const value = false;};
|
||||
|
||||
template <class CODER, class T>
|
||||
struct is_xpack_type_spec {static bool const value = false;};
|
||||
|
||||
|
||||
// for bitfield, declare raw type. thx https://stackoverflow.com/a/12199635/5845104
|
||||
template<int N> struct x_size { char value[N]; };
|
||||
x_size<1> x_decltype_encode(char);
|
||||
x_size<2> x_decltype_encode(signed char);
|
||||
x_size<3> x_decltype_encode(unsigned char);
|
||||
x_size<4> x_decltype_encode(short);
|
||||
x_size<5> x_decltype_encode(unsigned short);
|
||||
x_size<6> x_decltype_encode(int);
|
||||
x_size<7> x_decltype_encode(unsigned int);
|
||||
x_size<8> x_decltype_encode(long);
|
||||
x_size<9> x_decltype_encode(unsigned long);
|
||||
x_size<10> x_decltype_encode(long long);
|
||||
x_size<11> x_decltype_encode(unsigned long long);
|
||||
|
||||
template<int N> struct x_decltype_decode {};
|
||||
template <> struct x_decltype_decode<1> {typedef char type;};
|
||||
template <> struct x_decltype_decode<2> {typedef signed char type;};
|
||||
template <> struct x_decltype_decode<3> {typedef unsigned char type;};
|
||||
template <> struct x_decltype_decode<4> {typedef short type;};
|
||||
template <> struct x_decltype_decode<5> {typedef unsigned short type;};
|
||||
template <> struct x_decltype_decode<6> {typedef int type;};
|
||||
template <> struct x_decltype_decode<7> {typedef unsigned int type;};
|
||||
template <> struct x_decltype_decode<8> {typedef long type;};
|
||||
template <> struct x_decltype_decode<9> {typedef unsigned long type;};
|
||||
template <> struct x_decltype_decode<10> {typedef long long type;};
|
||||
template <> struct x_decltype_decode<11> {typedef unsigned long long type;};
|
||||
|
||||
class noncopyable {
|
||||
public:
|
||||
noncopyable(){}
|
||||
~noncopyable(){}
|
||||
private:
|
||||
noncopyable(const noncopyable&v);
|
||||
noncopyable& operator = (const noncopyable&v);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define x_pack_decltype(T) typename xpack::x_decltype_decode<sizeof(xpack::x_decltype_encode(T))>::type
|
||||
|
||||
|
||||
// fix SFINAE bug of vs2005, so vs2005(or pre version) not support XPACK_OUT define xtype.
|
||||
// can use custom
|
||||
// The priority of xtype is the highest
|
||||
#if defined _MSC_VER && _MSC_VER<=1400
|
||||
#define XPACK_IS_XTYPE(Coder, T) typename x_enable_if<is_xpack_xtype<T>::value && !is_xpack_type_spec<Coder, T>::value && !is_xpack_out<T>::value, bool>::type
|
||||
#else
|
||||
#define XPACK_IS_XTYPE(Coder, T) typename x_enable_if<is_xpack_xtype<T>::value && !is_xpack_type_spec<Coder, T>::value, bool>::type
|
||||
#endif
|
||||
|
||||
/*
|
||||
struct A {
|
||||
XPACK(...);
|
||||
};
|
||||
struct B : public A{
|
||||
};
|
||||
XPACK_OUT(B, ...);
|
||||
|
||||
in this case, B::__x_pack_value is true and should hit xpack_out, so
|
||||
XPACK_IS_XPACK need to add !is_xpack_out<T>::value
|
||||
*/
|
||||
|
||||
#define XPACK_IS_XOUT(T) typename x_enable_if<is_xpack_out<T>::value && !is_xpack_xtype<T>::value, bool>::type
|
||||
#define XPACK_IS_XPACK(T) typename x_enable_if<T::__x_pack_value && !is_xpack_out<T>::value && !is_xpack_xtype<T>::value, bool>::type
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
257
util/xpack/util.h
Executable file
257
util/xpack/util.h
Executable file
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_UTIL_H
|
||||
#define __X_PACK_UTIL_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "traits.h"
|
||||
#include "numeric.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
struct cmp_str {
|
||||
bool operator()(char const *a, char const *b) const {
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Util {
|
||||
public:
|
||||
static bool readfile(const std::string&fname, std::string&data) {
|
||||
std::ifstream fs(fname.c_str(), std::ifstream::binary);
|
||||
if (!fs) {
|
||||
std::string err = "Open file["+fname+"] fail.";
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
std::string _tmp((std::istreambuf_iterator<char>(fs)), std::istreambuf_iterator<char>());
|
||||
data.swap(_tmp);
|
||||
return true;
|
||||
}
|
||||
// if n<0 will split all
|
||||
static size_t split(std::vector<std::string>&slice, const std::string&str, char c, int n = -1) {
|
||||
size_t last = 0;
|
||||
size_t pos = 0;
|
||||
int cnt = 0;
|
||||
while (std::string::npos != (pos=str.find(c, last))) {
|
||||
slice.push_back(str.substr(last, pos-last));
|
||||
last = pos+1;
|
||||
++cnt;
|
||||
if (n>0 && n>=cnt) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
slice.push_back(str.substr(last));
|
||||
return slice.size();
|
||||
}
|
||||
|
||||
static size_t split(std::vector<std::string>&slice, const std::string&str, const std::string& sp, int n =-1) {
|
||||
size_t last = 0;
|
||||
size_t pos = 0;
|
||||
size_t len = sp.length();
|
||||
if (len == 0) {
|
||||
slice.push_back(str);
|
||||
return 1;
|
||||
}
|
||||
int cnt = 0;
|
||||
while (std::string::npos != (pos=str.find(sp, last))) {
|
||||
slice.push_back(str.substr(last, pos-last));
|
||||
last = pos+len;
|
||||
++cnt;
|
||||
if (n>0 && n>=cnt) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
slice.push_back(str.substr(last));
|
||||
return slice.size();
|
||||
}
|
||||
|
||||
// not support float.
|
||||
template <class T>
|
||||
static typename x_enable_if<numeric<T>::is_integer, std::string>::type itoa(const T&val) {
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
return std::to_string(val);
|
||||
#else
|
||||
char buf[128];
|
||||
size_t i = sizeof(buf)-1;
|
||||
|
||||
if (val == 0) {
|
||||
return std::string("0");
|
||||
}
|
||||
|
||||
T _tmp = val>=0?val:val*-1;
|
||||
while (_tmp > 0) {
|
||||
buf[i--] = char(int('0')+int(_tmp%10));
|
||||
_tmp /= 10;
|
||||
}
|
||||
if (val < 0) {
|
||||
buf[i--] = '-';
|
||||
}
|
||||
return std::string(&buf[i+1], sizeof(buf)-i-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
template <class E>
|
||||
inline static typename x_enable_if<std::is_enum<E>::value, std::string>::type itoa(const E& val) {
|
||||
return itoa((typename std::underlying_type<E>::type)val);
|
||||
}
|
||||
template <class E>
|
||||
static typename x_enable_if<std::is_enum<E>::value, bool>::type atoi(const std::string& key, E& val) {
|
||||
typename std::underlying_type<E>::type tmp;
|
||||
bool ret = atoi(key, tmp);
|
||||
if (ret) {
|
||||
val = (E)tmp;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
// not support float. and only decimal
|
||||
template <class T>
|
||||
static typename x_enable_if<numeric<T>::is_integer, bool>::type atoi(const std::string&s, T&val) {
|
||||
if (s.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
T _tmp = 0;
|
||||
size_t i = 0;
|
||||
if (s[0] == '-') {
|
||||
if (s.length() == 1) {
|
||||
return false;
|
||||
} else if (s.length()>2 && s[1]=='0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i=1; i<s.length(); ++i) {
|
||||
if (s[i]>='0' && s[i]<='9') {
|
||||
T _c = _tmp*10 - (s[i]-'0');
|
||||
if (_c < _tmp) {
|
||||
_tmp = _c;
|
||||
} else if (i > 0) {
|
||||
return false; // overflow
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (s[0] == '+') {
|
||||
++i;
|
||||
}
|
||||
if (s[i]=='0' && i+1<s.length()) {
|
||||
return false;
|
||||
}
|
||||
for (; i<s.length(); ++i) {
|
||||
if (s[i]>='0' && s[i]<='9') {
|
||||
T _c = _tmp*10 + (s[i]-'0');
|
||||
if (_c > _tmp) {
|
||||
_tmp = _c;
|
||||
} else if (i > 0) {
|
||||
return false; // overflow
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val = _tmp;
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
static typename x_enable_if<numeric<T>::is_integer, bool>::type atoi(const char*s, T&val) {
|
||||
if (NULL == s) {
|
||||
return false;
|
||||
}
|
||||
std::string _t(s);
|
||||
return atoi(_t, val);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#if defined(X_PACK_SUPPORT_CXX0X)
|
||||
template <class T>
|
||||
using x_shared_ptr = std::shared_ptr<T>;
|
||||
#elif defined(_GNU_SOURCE)
|
||||
// A very crude implementation of shared_ptr
|
||||
template <class T>
|
||||
class x_shared_ptr {
|
||||
public:
|
||||
x_shared_ptr(T *p = NULL):ptr(p) {
|
||||
if (NULL != p) {
|
||||
counter = new int;
|
||||
*counter = 1;
|
||||
} else {
|
||||
counter = NULL;
|
||||
}
|
||||
}
|
||||
x_shared_ptr(const x_shared_ptr &src) {
|
||||
ptr = src.ptr;
|
||||
counter = src.counter;
|
||||
add_ref(1);
|
||||
}
|
||||
~x_shared_ptr() {
|
||||
add_ref(-1);
|
||||
}
|
||||
x_shared_ptr& operator = (const x_shared_ptr &src) {
|
||||
add_ref(-1);
|
||||
ptr = src.ptr;
|
||||
counter = src.counter;
|
||||
add_ref(1);
|
||||
return *this;
|
||||
}
|
||||
void reset(T *p = NULL) {
|
||||
*this = x_shared_ptr(p);
|
||||
}
|
||||
T* operator ->() {
|
||||
return ptr;
|
||||
}
|
||||
T* get() {
|
||||
return ptr;
|
||||
}
|
||||
T& operator *() {
|
||||
return *ptr;
|
||||
}
|
||||
private:
|
||||
void add_ref(int cnt) {
|
||||
if (counter == NULL) {
|
||||
return;
|
||||
}
|
||||
int ncnt = __sync_add_and_fetch(counter, cnt);
|
||||
if (0 == ncnt) {
|
||||
delete counter;
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
T *ptr;
|
||||
mutable int *counter;
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
416
util/xpack/xdecoder.h
Executable file
416
util/xpack/xdecoder.h
Executable file
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_DECODER_H
|
||||
#define __X_PACK_DECODER_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include "extend.h"
|
||||
#include "traits.h"
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
#endif
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace xpack {
|
||||
|
||||
|
||||
/*
|
||||
Node need implement:
|
||||
static const char *Type() const; "json/bson/...."
|
||||
|
||||
operator bool() const; // check is a valid node
|
||||
bool IsNull() const; // only for json, others should always return false
|
||||
Node Find(decoder&, const char*key); // Find a child node(object)
|
||||
Node At(size_t index); // Find a child node(array)
|
||||
size_t Size(decoder&, ); // Get array size
|
||||
|
||||
// iterator
|
||||
Node Next(decoder&, const Node&p, Iterator&iter, std::string&key); // iter object
|
||||
|
||||
template <class T>
|
||||
bool Get(decoder&, T&val, const Extend*ext); // T is integer/double/std::string/bool
|
||||
*/
|
||||
template<class Node>
|
||||
class XDecoder {
|
||||
public:
|
||||
typedef XDecoder<Node> decoder;
|
||||
|
||||
XDecoder(const decoder* parent, const char* key, Node node):_p(parent),_k(key),_i(-1),_n(node) {}
|
||||
XDecoder(const decoder *parent, int index, Node node):_p(parent),_k(NULL),_i(index),_n(node) {}
|
||||
XDecoder():_i(-2){}
|
||||
|
||||
const char *Name() const {
|
||||
return Node::Name();
|
||||
}
|
||||
void decode_exception(const char* what, const char *key) const {
|
||||
std::string err;
|
||||
err.reserve(128);
|
||||
if (NULL != what) {
|
||||
err.append(what);
|
||||
}
|
||||
err.append(". (path:");
|
||||
|
||||
std::string p = path();
|
||||
err.append(p);
|
||||
if (NULL != key) {
|
||||
if (!p.empty()) {
|
||||
err.append(".");
|
||||
}
|
||||
err.append(key);
|
||||
}
|
||||
|
||||
err.append(")");
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
// find by key
|
||||
decoder Find(const char *key, const Extend *ext) {
|
||||
Node child = _n.Find(*this, key, ext);
|
||||
if (child){
|
||||
return XDecoder(this, key, child);
|
||||
} else if (Extend::Mandatory(ext)) {
|
||||
decode_exception("mandatory key not found", key);
|
||||
}
|
||||
|
||||
return XDecoder();
|
||||
}
|
||||
operator bool() const {
|
||||
return _i != -2;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
bool decode(const char*key, T&val, const Extend*ext) {
|
||||
decoder child = Find(key, ext);
|
||||
if (child) {
|
||||
return child.decode_type(val, ext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool decode(T &val, const Extend*ext) {
|
||||
return this->decode_type(val, ext);
|
||||
}
|
||||
|
||||
// class/struct that defined macro XPACK, !is_xpack_out to avoid inherit __x_pack_value
|
||||
template <class T>
|
||||
inline typename x_enable_if<T::__x_pack_value && !is_xpack_out<T>::value, bool>::type decode_struct(T& val, const Extend *ext) {
|
||||
return val.__x_pack_decode(*this, val, ext);
|
||||
}
|
||||
// class/struct that defined macro XPACK_OUT
|
||||
template <class T>
|
||||
inline typename x_enable_if<is_xpack_out<T>::value, bool>::type decode_struct(T& val, const Extend *ext) {
|
||||
return __x_pack_decode_out(*this, val, ext);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool decode_struct(const char*key, T&val, const Extend *ext) {
|
||||
decoder child = Find(key, ext);
|
||||
if (child) {
|
||||
return child.decode_struct(val, ext);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// numeric
|
||||
template <class T>
|
||||
inline typename x_enable_if<numeric<T>::value, bool>::type decode_type(T&val, const Extend *ext) {
|
||||
return _n.Get(*this, val, ext);
|
||||
}
|
||||
// std::string
|
||||
inline bool decode_type(std::string&val, const Extend *ext) {
|
||||
return _n.Get(*this, val, ext);
|
||||
}
|
||||
// std::string
|
||||
inline bool decode_type(bool&val, const Extend *ext) {
|
||||
return _n.Get(*this, val, ext);
|
||||
}
|
||||
// array
|
||||
template <class T, size_t N>
|
||||
inline bool decode_type(T (&val)[N], const Extend *ext) {
|
||||
return this->decode_array(val, N, ext);
|
||||
}
|
||||
// vector
|
||||
template <class T>
|
||||
inline bool decode_type(std::vector<T> &val, const Extend *ext) {
|
||||
return this->decode_vector(val, ext);
|
||||
}
|
||||
// list
|
||||
template <class T>
|
||||
inline bool decode_type(std::list<T> &val, const Extend *ext) {
|
||||
return this->decode_list<std::list<T>, T>(val, ext);
|
||||
}
|
||||
// set
|
||||
template <class T>
|
||||
inline bool decode_type(std::set<T> &val, const Extend *ext) {
|
||||
return this->decode_list<std::set<T>, T>(val, ext);
|
||||
}
|
||||
// map
|
||||
template <class K, class V>
|
||||
inline bool decode_type(std::map<K, V> &val, const Extend *ext) {
|
||||
return decode_map<std::map<K, V>, K, V>(val, ext);
|
||||
}
|
||||
// XPACK or XPACK_OUT and not XTYPE
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) decode_type(T&val, const Extend *ext) {
|
||||
return decode_struct(val, ext);
|
||||
}
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) decode_type(T&val, const Extend *ext) {
|
||||
return decode_struct(val, ext);
|
||||
}
|
||||
// xtype. add && !is_xpack_out<T>::value to fix SFINAE bug of vs2005
|
||||
template <class T>
|
||||
inline XPACK_IS_XTYPE(Node, T) decode_type(T& val, const Extend *ext) {
|
||||
return xpack_xtype_decode(*this, val, ext);
|
||||
}
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
// unordered_map
|
||||
template <class K, class V>
|
||||
inline bool decode_type(std::unordered_map<K, V> &val, const Extend *ext) {
|
||||
return decode_map<std::unordered_map<K, V>, K, V>(val, ext);
|
||||
}
|
||||
// shared_ptr
|
||||
template <class T>
|
||||
bool decode_type(std::shared_ptr<T>& val, const Extend *ext) {
|
||||
bool ret = false;
|
||||
if (!_n.IsNull()) {
|
||||
val.reset(new T);
|
||||
ret = this->decode_type(*val, ext);
|
||||
if (!ret) {
|
||||
val.reset();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// enum is_enum implementation is too complicated, so in c++03, we use macro E
|
||||
template <class T>
|
||||
inline typename x_enable_if<std::is_enum<T>::value && !is_xpack_xtype<T>::value, bool>::type decode_type(T& val, const Extend *ext) {
|
||||
typename std::underlying_type<T>::type tmp;
|
||||
bool ret = this->decode_type(tmp, ext);
|
||||
if (ret) {
|
||||
val = (T)tmp;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// assert pointer
|
||||
template <class T>
|
||||
typename x_enable_if<std::is_pointer<T>::value, bool>::type decode_type(T &val, const Extend *ext) {
|
||||
static_assert(!std::is_pointer<T>::value, "not support pointer, use shared_ptr please");
|
||||
(void)val;(void)ext;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////// QT ///////////////////////////////
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
bool decode_type(QString &val, const Extend *ext) {
|
||||
std::string str;
|
||||
bool ret = this->decode_type(str, ext);
|
||||
if (ret) {
|
||||
val = QString::fromStdString(str);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
template<typename T>
|
||||
inline bool decode_type(QList<T> &val, const Extend *ext) {
|
||||
return this->decode_list<QList<T>, T>(val, ext);
|
||||
}
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) //https://www.qt.io/blog/qlist-changes-in-qt-6
|
||||
template<typename T>
|
||||
inline bool decode_type(QVector<T> &val, const Extend *ext) {
|
||||
return this->decode_vector(val, ext);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename K, typename V>
|
||||
inline bool decode_type(QMap<K, V> &val, const Extend *ext) {
|
||||
return decode_map<QMap<K, V>, K, V>(val, ext);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline typename x_enable_if<is_xpack_type_spec<Node, T>::value, bool>::type decode_type(T&val, const Extend *ext) {
|
||||
return _n.decode_type_spec(val, ext);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
template <class T>
|
||||
bool decode_array(T *val, size_t N, const Extend *ext) {
|
||||
size_t mx = _n.Size(*this);
|
||||
mx = mx>N?N:mx;
|
||||
|
||||
for (size_t i=0; i<mx; ++i) {
|
||||
this->at(i, ext).decode_type(val[i], ext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// char[] is special
|
||||
bool decode_array(char* val, size_t N, const Extend *ext) {
|
||||
std::string str;
|
||||
bool ret = this->decode_type(str, ext);
|
||||
if (ret) {
|
||||
size_t mx = str.length();
|
||||
mx = mx>N-1?N-1:mx;
|
||||
strncpy(val, str.data(), mx);
|
||||
val[mx] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
template <class Vector>
|
||||
bool decode_vector(Vector &val, const Extend *ext) {
|
||||
size_t s = _n.Size(*this);
|
||||
val.resize(s);
|
||||
for (size_t i=0; i<s; ++i) {
|
||||
this->at(i, ext).decode_type(val[i], ext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// list
|
||||
template <class List, class Elem>
|
||||
bool decode_list(List &val, const Extend *ext) {
|
||||
size_t s = _n.Size(*this);
|
||||
for (size_t i=0; i<s; ++i) {
|
||||
Elem _t;
|
||||
this->at(i, ext).decode_type(_t, ext);
|
||||
this->add_ele(val, _t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// map
|
||||
template <class Map, class K, class V>
|
||||
bool decode_map(Map &val, const Extend *ext) {
|
||||
typename Node::Iterator iter;
|
||||
std::string key;
|
||||
Node tmp = _n.Next(*this, _n, iter, key);
|
||||
while (tmp) {
|
||||
K k;
|
||||
V v;
|
||||
if (keyConvert(key, k) && XDecoder(this, key.c_str(), tmp).decode_type(v, ext)) {
|
||||
val[k] = v;
|
||||
}
|
||||
tmp = tmp.Next(*this, _n, iter, key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////// container process //////
|
||||
template <class T>
|
||||
inline void add_ele(std::list<T>&val, T &t) {
|
||||
val.push_back(t);
|
||||
}
|
||||
template <class T>
|
||||
inline void add_ele(std::set<T>&val, T &t) {
|
||||
val.insert(t);
|
||||
}
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
template <class T>
|
||||
inline void add_ele(QList<T>&val, T &t) {
|
||||
val.push_back(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// convert map key
|
||||
inline bool keyConvert(std::string&s, std::string&key) {
|
||||
key.swap(s);
|
||||
return true;
|
||||
}
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
inline bool keyConvert(std::string&s, QString &key) {
|
||||
key = QString::fromStdString(s);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
// enum is_enum implementation is too complicated, so not support in c++03
|
||||
template <class T>
|
||||
typename x_enable_if<std::is_enum<T>::value, bool>::type keyConvert(std::string&s, T&key) {
|
||||
typename std::underlying_type<T>::type tmp;
|
||||
bool ret = Util::atoi(s, tmp);
|
||||
if (ret) {
|
||||
key = (T)tmp;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
template <class T>
|
||||
inline typename x_enable_if<numeric<T>::is_integer, bool>::type keyConvert(std::string&s, T&key) {
|
||||
return Util::atoi(s, key);
|
||||
}
|
||||
|
||||
// index
|
||||
decoder at(size_t i, const Extend *ext) {
|
||||
(void)ext;
|
||||
return XDecoder(this, (int)i, _n.At(i));
|
||||
}
|
||||
|
||||
// exception process
|
||||
std::string path() const {
|
||||
std::vector<std::string> nodes;
|
||||
const decoder* tmp = this;
|
||||
while (tmp) {
|
||||
std::string k;
|
||||
k.reserve(32);
|
||||
if (NULL != tmp->_k) {
|
||||
if (NULL!=tmp->_p && NULL!=tmp->_p->_p) {
|
||||
k.append(".");
|
||||
}
|
||||
k.append(tmp->_k);
|
||||
} else if (_i >= 0) {
|
||||
k.append("[").append(Util::itoa(tmp->_i)).append("]");
|
||||
}
|
||||
nodes.push_back(k);
|
||||
tmp = tmp->_p;
|
||||
}
|
||||
std::string p;
|
||||
p.reserve(64);
|
||||
for (int i=(int)nodes.size()-1; i>=0; --i) {
|
||||
p.append(nodes[i]);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
const decoder* _p;
|
||||
const char* _k;
|
||||
int _i;
|
||||
Node _n;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
369
util/xpack/xencoder.h
Executable file
369
util/xpack/xencoder.h
Executable file
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_ENCODER_H
|
||||
#define __X_PACK_ENCODER_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#include "extend.h"
|
||||
#include "traits.h"
|
||||
#include "numeric.h"
|
||||
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
#endif
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace xpack {
|
||||
|
||||
/*
|
||||
DOC need implement:
|
||||
const char *Name() const; "json/bson/...."
|
||||
const static bool support_null = true/false;
|
||||
|
||||
ArrayBegin(const char *key, const Extend *ext) begin encode array
|
||||
ArrayEnd(const char *key, const Extend *ext) end encode array
|
||||
|
||||
ObjectBegin(const char *key, const Extend *ext) begin encode object
|
||||
ObjectEnd(const char *key, const Extend *ext) end encode object
|
||||
|
||||
WriteNull(const char *key, const Extend *ext)
|
||||
|
||||
std::string String() return the encode result
|
||||
|
||||
// basic type
|
||||
bool encode_bool(const char*key, const bool&val, const Extend *ext);
|
||||
bool encode_string(const char*key, const std::string&val, const Extend *ext);
|
||||
bool encode_number(const char*key, const T&val, const Extend *ext);
|
||||
*/
|
||||
template<typename Writer>
|
||||
class XEncoder :private noncopyable{
|
||||
typedef XEncoder<Writer> encoder;
|
||||
Writer &_w;
|
||||
|
||||
public:
|
||||
XEncoder(Writer &w):_w(w){}
|
||||
|
||||
const char *Name() const {
|
||||
return Writer::Name();
|
||||
}
|
||||
|
||||
// After calling String, this Encoder has finished its work and should not be used anymore
|
||||
inline std::string String() {
|
||||
return _w.String();
|
||||
}
|
||||
|
||||
#define XPACK_WRITE_EMPTY(cond) \
|
||||
if (cond) { \
|
||||
if (Extend::OmitEmpty(ext)) { \
|
||||
return false;\
|
||||
} else if (Writer::support_null && Extend::EmptyNull(ext)) {\
|
||||
return _w.WriteNull(key, ext);\
|
||||
}\
|
||||
}
|
||||
|
||||
// basic type
|
||||
bool encode(const char*key, const bool &val, const Extend *ext) {
|
||||
XPACK_WRITE_EMPTY(!val);
|
||||
return _w.encode_bool(key, val, ext);
|
||||
}
|
||||
bool encode(const char*key, const std::string &val, const Extend *ext) {
|
||||
XPACK_WRITE_EMPTY(val.empty());
|
||||
return _w.encode_string(key, val, ext);
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::value, bool>::type encode(const char*key, const T&val, const Extend *ext) {
|
||||
XPACK_WRITE_EMPTY(val == 0);
|
||||
return _w.encode_number(key, val, ext);
|
||||
}
|
||||
|
||||
// array
|
||||
template <class T, size_t N>
|
||||
inline bool encode(const char*key, const T (&val)[N], const Extend *ext) {
|
||||
return this->encode(key, val, N, ext);
|
||||
}
|
||||
template <class T>
|
||||
bool encode(const char *key, const T *val, size_t N, const Extend *ext) {
|
||||
XPACK_WRITE_EMPTY((N==0))
|
||||
|
||||
_w.ArrayBegin(key, ext);
|
||||
for (size_t i=0; i<N; ++i) {
|
||||
this->encode(_w.IndexKey(i), val[i], NULL);
|
||||
}
|
||||
_w.ArrayEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
inline bool encode(const char*key, const char *val, size_t N, const Extend *ext) {
|
||||
(void)N;
|
||||
std::string str(val);
|
||||
return this->encode(key, str, ext);
|
||||
}
|
||||
// vector
|
||||
template <class T>
|
||||
inline bool encode(const char*key, const std::vector<T> &val, const Extend *ext) {
|
||||
return encode_list<std::vector<T> >(key, val, ext);
|
||||
}
|
||||
// list
|
||||
template <class T>
|
||||
inline bool encode(const char*key, const std::list<T> &val, const Extend *ext) {
|
||||
return encode_list<std::list<T> >(key, val, ext);
|
||||
}
|
||||
// set
|
||||
template <class T>
|
||||
inline bool encode(const char*key, const std::set<T> &val, const Extend *ext) {
|
||||
return encode_list<std::set<T> >(key, val, ext);
|
||||
}
|
||||
// map
|
||||
template <class K, class V>
|
||||
inline bool encode(const char*key, const std::map<K, V> &val, const Extend *ext) {
|
||||
return encode_map<const std::map<K, V> >(key, val, ext);
|
||||
}
|
||||
// class/struct that defined XPACK
|
||||
template <class T>
|
||||
inline XPACK_IS_XPACK(T) encode(const char*key, const T& val, const Extend *ext) {
|
||||
return encode_struct(key, val, ext);
|
||||
}
|
||||
// class/struct that defined XPACK_OUT
|
||||
template <class T>
|
||||
inline XPACK_IS_XOUT(T) encode(const char*key, const T& val, const Extend *ext) {
|
||||
return encode_struct(key, val, ext);
|
||||
}
|
||||
// xtype
|
||||
template <class T>
|
||||
inline XPACK_IS_XTYPE(Writer, T) encode(const char*key, const T& val, const Extend *ext) {
|
||||
return encode_xtype(key, val, ext);
|
||||
}
|
||||
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
// unordered_map
|
||||
template <class K, class V>
|
||||
inline bool encode(const char*key, const std::unordered_map<K, V> &val, const Extend *ext) {
|
||||
return encode_map<const std::unordered_map<K, V>>(key, val, ext);
|
||||
}
|
||||
// shared_ptr
|
||||
template <class T>
|
||||
bool encode(const char*key, const std::shared_ptr<T>& val, const Extend *ext) {
|
||||
if (val.get() == NULL) { // if shared ptr is null
|
||||
return _w.WriteNull(key, ext);
|
||||
}
|
||||
|
||||
return this->encode(key, *val, ext);
|
||||
}
|
||||
// enum
|
||||
template <class T>
|
||||
typename x_enable_if<std::is_enum<T>::value && !is_xpack_xtype<T>::value, bool>::type encode(const char*key, const T& val, const Extend *ext) {
|
||||
typename std::underlying_type<T>::type tmp = (typename std::underlying_type<T>::type)val;
|
||||
return this->encode(key, tmp, ext);
|
||||
}
|
||||
// assert pointer
|
||||
template <class T>
|
||||
typename x_enable_if<std::is_pointer<T>::value, bool>::type encode(const char*key, const T &val, const Extend *ext) {
|
||||
static_assert(!std::is_pointer<T>::value, "no support pointer, use shared_ptr please");
|
||||
(void)key;(void)val;(void)ext;
|
||||
return false;
|
||||
}
|
||||
#endif // cxx
|
||||
template <class T>
|
||||
inline bool encode_xtype(const char*key, const T &val, const Extend *ext) {
|
||||
return xpack_xtype_encode(*this, key, val, ext);
|
||||
}
|
||||
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
bool encode(const char*key, const QString &val, const Extend *ext) {
|
||||
std::string str = val.toStdString();
|
||||
return this->encode(key, str, ext);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool encode(const char*key, const QList<T>&val, const Extend *ext) {
|
||||
return encode_list<QList<T> >(key, val, ext);
|
||||
}
|
||||
template<class K, class V>
|
||||
bool encode(const char*key, const QMap<K, V>&val, const Extend *ext) {
|
||||
return encode_qmap<const QMap<K, V> >(key, val, ext);
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) //https://www.qt.io/blog/qlist-changes-in-qt-6
|
||||
template<typename T>
|
||||
bool encode(const char*key, const QVector<T>&val, const Extend *ext) {
|
||||
return encode_list<QVector<T> >(key, val, ext);
|
||||
}
|
||||
#endif // Qt5
|
||||
|
||||
#endif // Qt
|
||||
|
||||
template <typename T>
|
||||
inline typename x_enable_if<is_xpack_type_spec<Writer, T>::value, bool>::type encode(const char*key, const T&val, const Extend *ext) {
|
||||
return _w.encode_type_spec(key, val, ext);
|
||||
}
|
||||
|
||||
// only for class/struct that defined XPACK
|
||||
template <class T>
|
||||
typename x_enable_if<T::__x_pack_value && !is_xpack_out<T>::value, bool>::type encode_struct(const char*key, const T& val, const Extend *ext) {
|
||||
bool inherit = 0!=(X_PACK_CTRL_FLAG_INHERIT&Extend::CtrlFlag(ext));
|
||||
if (!inherit) {
|
||||
_w.ObjectBegin(key, ext);
|
||||
}
|
||||
bool ret = val.__x_pack_encode(*this, val, ext);
|
||||
if (!inherit) {
|
||||
_w.ObjectEnd(key, ext);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// only for class/struct that defined XPACK_OUT
|
||||
template <class T>
|
||||
typename x_enable_if<is_xpack_out<T>::value, bool>::type encode_struct(const char*key, const T& val, const Extend *ext) {
|
||||
bool inherit = 0!=(X_PACK_CTRL_FLAG_INHERIT&Extend::CtrlFlag(ext));
|
||||
|
||||
if (!inherit) {
|
||||
_w.ObjectBegin(key, ext);
|
||||
}
|
||||
bool ret = __x_pack_encode_out(*this, val, ext);
|
||||
if (!inherit) {
|
||||
_w.ObjectEnd(key, ext);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// wrapper for encode manual
|
||||
inline void ArrayBegin(const char *key, const Extend *ext) {
|
||||
_w.ArrayBegin(key, ext);
|
||||
}
|
||||
inline void ArrayEnd(const char *key, const Extend *ext) {
|
||||
_w.ArrayEnd(key, ext);
|
||||
}
|
||||
inline void ObjectBegin(const char *key, const Extend *ext) {
|
||||
_w.ObjectBegin(key, ext);
|
||||
}
|
||||
inline void ObjectEnd(const char *key, const Extend *ext) {
|
||||
_w.ObjectEnd(key, ext);
|
||||
}
|
||||
inline void WriteNull(const char *key, const Extend *ext) {
|
||||
_w.WriteNull(key, ext);
|
||||
}
|
||||
template <class T>
|
||||
encoder& add(const char *key, const T&val, const Extend *ext=NULL) {
|
||||
this->encode(key, val, ext);
|
||||
return *this;
|
||||
}
|
||||
// object begin
|
||||
encoder& ob(const char *key) {
|
||||
this->ObjectBegin(key, NULL);
|
||||
return *this;
|
||||
}
|
||||
// object end
|
||||
encoder& oe(const char *key=NULL) {
|
||||
this->ObjectEnd(key, NULL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// array begin
|
||||
encoder& ab(const char *key) {
|
||||
this->ArrayBegin(key, NULL);
|
||||
return *this;
|
||||
}
|
||||
// array end
|
||||
encoder& ae(const char *key=NULL) {
|
||||
this->ArrayEnd(key, NULL);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// list
|
||||
template <class LIST>
|
||||
bool encode_list(const char*key, const LIST &val, const Extend *ext) {
|
||||
size_t s = val.size();
|
||||
XPACK_WRITE_EMPTY((s==0))
|
||||
|
||||
_w.ArrayBegin(key, ext);
|
||||
size_t i = 0;
|
||||
for (typename LIST::const_iterator it=val.begin(); it!=val.end(); ++it, ++i) {
|
||||
this->encode(_w.IndexKey(i), *it, NULL);
|
||||
}
|
||||
_w.ArrayEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// map
|
||||
template <class Map>
|
||||
bool encode_map(const char*key, Map &val, const Extend *ext) {
|
||||
size_t s = val.size();
|
||||
XPACK_WRITE_EMPTY((s==0))
|
||||
|
||||
_w.ObjectBegin(key, ext);
|
||||
for (typename Map::const_iterator it=val.begin(); it!=val.end(); ++it) {
|
||||
this->encode(keyConvert(it->first).c_str(), it->second, NULL);
|
||||
}
|
||||
_w.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// qmap
|
||||
template <class Map>
|
||||
bool encode_qmap(const char*key, Map &val, const Extend *ext) {
|
||||
size_t s = val.size();
|
||||
XPACK_WRITE_EMPTY((s==0))
|
||||
|
||||
_w.ObjectBegin(key, ext);
|
||||
for (typename Map::const_iterator it=val.begin(); it!=val.end(); ++it) {
|
||||
this->encode(keyConvert(it.key()).c_str(), it.value(), NULL);
|
||||
}
|
||||
_w.ObjectEnd(key, ext);
|
||||
return true;
|
||||
}
|
||||
|
||||
// convert map key
|
||||
inline std::string keyConvert(const std::string&key) {
|
||||
return key;
|
||||
}
|
||||
#ifdef XPACK_SUPPORT_QT
|
||||
inline std::string keyConvert(const QString &key) {
|
||||
return key.toStdString();
|
||||
}
|
||||
#endif
|
||||
#ifdef X_PACK_SUPPORT_CXX0X
|
||||
// enum is_enum implementation is too complicated, so not support in c++03
|
||||
template <class T>
|
||||
typename x_enable_if<std::is_enum<T>::value, std::string>::type keyConvert(const T&key) {
|
||||
typename std::underlying_type<T>::type tmp = (typename std::underlying_type<T>::type)key;
|
||||
return Util::itoa(tmp);
|
||||
}
|
||||
#endif
|
||||
template <class T>
|
||||
inline typename x_enable_if<numeric<T>::is_integer, std::string>::type keyConvert(const T&key) {
|
||||
return Util::itoa(key);
|
||||
}
|
||||
|
||||
#undef XPACK_WRITE_EMPTY
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
79
util/xpack/xml.h
Executable file
79
util/xpack/xml.h
Executable file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_XML_H
|
||||
#define __X_PACK_XML_H
|
||||
|
||||
#include "xml_decoder.h"
|
||||
#include "xml_encoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
namespace xpack {
|
||||
/*
|
||||
for xml like
|
||||
<user>
|
||||
<name>Pony</name>
|
||||
<age>20</age>
|
||||
</user>
|
||||
|
||||
Just define such a structure
|
||||
struct User {
|
||||
string name;
|
||||
int age;
|
||||
XPACK(O(name, age));
|
||||
};
|
||||
|
||||
!!!!NO NEED!!! to define:
|
||||
struct Data {
|
||||
User user;
|
||||
XPACK(O(user));
|
||||
};
|
||||
|
||||
xml::decode will skip the root node, so for the xml defined above,
|
||||
it only needs to be decode like this:
|
||||
User u;
|
||||
xpack::xml::decode(str, u);
|
||||
*/
|
||||
|
||||
class xml {
|
||||
public:
|
||||
template <class T>
|
||||
static void decode(const std::string &data, T &val) {
|
||||
XmlDecoder de;
|
||||
de.decode(data, val);
|
||||
}
|
||||
template <class T>
|
||||
static void decode_file(const std::string &file_name, T &val) {
|
||||
XmlDecoder de;
|
||||
de.decode_file(file_name, val);
|
||||
}
|
||||
template <class T>
|
||||
static std::string encode(const T &val, const std::string&root) {
|
||||
XmlEncoder en;
|
||||
return en.encode(val, root);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string encode(const T &val, const std::string&root, int flag, int indentCount, char indentChar) {
|
||||
(void)flag;
|
||||
XmlEncoder en(indentCount, indentChar);
|
||||
return en.encode(val, root);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
254
util/xpack/xml_decoder.h
Executable file
254
util/xpack/xml_decoder.h
Executable file
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_XML_DECODER_H
|
||||
#define __X_PACK_XML_DECODER_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
|
||||
#include "rapidxml/rapidxml.hpp"
|
||||
|
||||
#include "xdecoder.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class XmlNode {
|
||||
typedef rapidxml::xml_node<> Node;
|
||||
typedef XDecoder<XmlNode> decoder;
|
||||
public:
|
||||
typedef size_t Iterator;
|
||||
|
||||
public:
|
||||
XmlNode(Node *n=NULL):node(n), attr(NULL), inited(false) {}
|
||||
|
||||
inline static const char * Name() {
|
||||
return "xml";
|
||||
}
|
||||
operator bool() const {
|
||||
return node != NULL;
|
||||
}
|
||||
bool IsNull() const {
|
||||
return false;
|
||||
}
|
||||
XmlNode Find(decoder&de, const char*key, const Extend *ext) {
|
||||
(void)de;
|
||||
if (!inited) {
|
||||
this->init();
|
||||
}
|
||||
if (Extend::XmlContent(ext)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_index::iterator iter;
|
||||
if (_childs_index.end() != (iter=_childs_index.find(key))) {
|
||||
bool sbs = Extend::AliasFlag(ext, "xml", "sbs");
|
||||
if (!sbs) {
|
||||
return XmlNode(_childs[iter->second]);
|
||||
} else {
|
||||
XmlNode node(_childs[iter->second]);
|
||||
node.initsbs(*this, key);
|
||||
return node;
|
||||
}
|
||||
} else { // sbs not support attribute
|
||||
XmlNode tmp;
|
||||
tmp.attr = node->first_attribute(key);
|
||||
if (NULL != tmp.attr) {
|
||||
tmp.node = this->node;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
size_t Size(decoder&de) {
|
||||
(void)de;
|
||||
if (!inited) {
|
||||
this->init();
|
||||
}
|
||||
return _childs.size();
|
||||
}
|
||||
XmlNode At(size_t index) const { // no exception
|
||||
return XmlNode(_childs[index]);
|
||||
}
|
||||
// if child node defined sbs, results can be confusing
|
||||
XmlNode Next(decoder&de, XmlNode&p, Iterator&iter, std::string&key) {
|
||||
(void)de;
|
||||
if (!p.inited) {
|
||||
p.init();
|
||||
}
|
||||
if (node != NULL) {
|
||||
if (node != p.node) {
|
||||
++iter;
|
||||
} else {
|
||||
iter = 0;
|
||||
}
|
||||
|
||||
if (iter < p._childs.size()) {
|
||||
key = p._childs[iter]->name();
|
||||
return XmlNode(p._childs[iter]);
|
||||
}
|
||||
}
|
||||
return XmlNode();
|
||||
}
|
||||
bool Get(decoder&de, std::string&val, const Extend*ext) {
|
||||
if (!Extend::AliasFlag(ext, "xml", "cdata")) {
|
||||
val = get_val(Extend::XmlContent(ext));
|
||||
} else {
|
||||
const Node *tmp = node->first_node();
|
||||
if (NULL != tmp) {
|
||||
if (tmp->type() == rapidxml::node_cdata || tmp->type() == rapidxml::node_data) {
|
||||
val = tmp->value();
|
||||
} else {
|
||||
de.decode_exception("not cdata type", NULL);
|
||||
}
|
||||
} else { // if node contain text not CDATA, get it
|
||||
val = node->value();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Get(decoder&de, bool &val, const Extend*ext) {
|
||||
(void)ext;
|
||||
std::string v = get_val(Extend::XmlContent(ext));
|
||||
if (v=="1" || v=="true" || v=="TRUE" || v=="True") {
|
||||
val = true;
|
||||
} else if (v=="0" || v=="false" || v=="FALSE" || v=="False") {
|
||||
val = false;
|
||||
} else {
|
||||
de.decode_exception("parse bool fail.", NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)ext;
|
||||
std::string v = get_val(Extend::XmlContent(ext));
|
||||
if (Util::atoi(v, val)) {
|
||||
return true;
|
||||
} else {
|
||||
de.decode_exception("parse int fail. not integer or overflow", NULL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type Get(decoder&de, T &val, const Extend*ext){
|
||||
(void)ext;
|
||||
std::string v = get_val(Extend::XmlContent(ext));
|
||||
if (1==v.length() && v[0]=='-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *data = v.c_str();
|
||||
char *end;
|
||||
double d = strtod(data, &end);
|
||||
if ((size_t)(end-data) == v.length()) {
|
||||
val = (T)d;
|
||||
return true;
|
||||
}
|
||||
de.decode_exception("parse double fail.", NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::map<const char*, size_t, cmp_str> node_index; // index of _childs
|
||||
|
||||
void init() {
|
||||
inited = true;
|
||||
if (NULL != node) {
|
||||
Node *tmp = node->first_node();
|
||||
for (size_t i=0; tmp; tmp=tmp->next_sibling(), ++i) {
|
||||
_childs.push_back(tmp);
|
||||
_childs_index[tmp->name()] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
void initsbs(const XmlNode&parent, const char *key) {
|
||||
inited = true;
|
||||
for (size_t i=0; i<parent._childs.size(); ++i) {
|
||||
if (0 == strcmp(key, parent._childs[i]->name())) {
|
||||
_childs.push_back(parent._childs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_val(bool forceContent=false) {
|
||||
if (forceContent || attr==NULL) {
|
||||
return node->value();
|
||||
} else if (attr != NULL) {
|
||||
return attr->value();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const Node* node; // current node
|
||||
rapidxml::xml_attribute<char> *attr;
|
||||
bool inited; // delay init to avoid copy _childs and _childs_index
|
||||
|
||||
std::vector<Node*> _childs; // childs
|
||||
node_index _childs_index;
|
||||
};
|
||||
|
||||
|
||||
class XmlDecoder {
|
||||
public:
|
||||
template <class T>
|
||||
bool decode(const std::string&str, T&val, bool with_root=false) {
|
||||
std::string tmp = str;
|
||||
return this->decode_indata(tmp, val, with_root);
|
||||
}
|
||||
template <class T>
|
||||
bool decode_file(const std::string&fname, T&val, bool with_root=false) {
|
||||
std::string data;
|
||||
bool ret = Util::readfile(fname, data);
|
||||
if (ret) {
|
||||
ret = this->decode_indata(data, val, with_root);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
template <class T>
|
||||
bool decode_indata(std::string&str, T&val, bool with_root=false) {
|
||||
rapidxml::xml_document<> de;
|
||||
std::string err;
|
||||
try {
|
||||
de.parse<0>((char*)str.c_str());
|
||||
} catch (const rapidxml::parse_error&e) {
|
||||
err = std::string("parse xml fail. err=")+e.what()+". "+std::string(e.where<char>()).substr(0, 32);
|
||||
} catch (const std::exception&e) {
|
||||
err = std::string("parse xml fail. unknow exception. err=")+e.what();
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
if (!with_root) {
|
||||
XmlNode node(de.first_node());
|
||||
return XDecoder<XmlNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
} else {
|
||||
XmlNode node(&de);
|
||||
return XDecoder<XmlNode>(NULL, (const char*)NULL, node).decode(val, NULL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
371
util/xpack/xml_encoder.h
Executable file
371
util/xpack/xml_encoder.h
Executable file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_XML_ENCODER_H
|
||||
#define __X_PACK_XML_ENCODER_H
|
||||
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include "xencoder.h"
|
||||
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class XmlWriter {
|
||||
struct Attr {
|
||||
const char* key;
|
||||
std::string val;
|
||||
Attr(const char*_key, const std::string&_val):key(_key), val(_val){}
|
||||
};
|
||||
struct Node {
|
||||
Node(const char*_key=NULL, const Extend *ext=NULL) {
|
||||
(void)ext;
|
||||
if (_key != NULL) {
|
||||
key = _key;
|
||||
}
|
||||
}
|
||||
~Node() {
|
||||
std::list<Node*>::iterator it;
|
||||
for (it = childs.begin(); it!=childs.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
std::string key; // key for this node
|
||||
std::string val; // value for this node, only for leaf node
|
||||
std::list<Attr> attrs; // attribute
|
||||
std::list<Node*> childs;// child nodes
|
||||
|
||||
std::string vec_key; // key for vector
|
||||
};
|
||||
|
||||
friend class XEncoder<XmlWriter>;
|
||||
friend class XmlEncoder;
|
||||
const static bool support_null = false;
|
||||
public:
|
||||
XmlWriter(int indentCount = -1, char indentChar = ' ', int decimalPlaces = 324):_indentCount(indentCount),_indentChar(indentChar),_decimalPlaces(decimalPlaces) {
|
||||
if (_indentCount > 0) {
|
||||
if (_indentChar!=' ' && _indentChar!='\t') {
|
||||
throw std::runtime_error("indentChar must be space or tab");
|
||||
}
|
||||
}
|
||||
_cur = &_root;
|
||||
}
|
||||
private:
|
||||
std::string String() {
|
||||
merge();
|
||||
return _output;
|
||||
}
|
||||
inline static const char *Name() {
|
||||
return "xml";
|
||||
}
|
||||
inline const char *IndexKey(size_t index) {
|
||||
(void)index;
|
||||
return _cur->vec_key.c_str();
|
||||
}
|
||||
void ArrayBegin(const char *key, const Extend *ext) {
|
||||
Node *n = new Node(key, ext);
|
||||
|
||||
if (NULL!=_cur && !_cur->vec_key.empty()) { // vector<vector<...>>
|
||||
n->vec_key = n->key;
|
||||
} else if (NULL != ext && NULL != ext->alias) {
|
||||
if (!ext->alias->Flag("xml", "vl", &n->vec_key)) { // forward compatible, support vector label
|
||||
if (ext->alias->Flag("xml", "sbs")) { // no top label, vector item will side by side
|
||||
n->vec_key.swap(n->key); // n->vec_key=key and n->key="";
|
||||
} else {
|
||||
n->vec_key = n->key; // has top level
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n->vec_key = n->key;
|
||||
}
|
||||
|
||||
_cur->childs.push_back(n);
|
||||
|
||||
_stack.push_back(_cur);
|
||||
_cur = n;
|
||||
}
|
||||
void ArrayEnd(const char *key, const Extend *ext) {
|
||||
(void)key;
|
||||
(void)ext;
|
||||
_cur = _stack.back();
|
||||
_stack.pop_back();
|
||||
}
|
||||
void ObjectBegin(const char *key, const Extend *ext) {
|
||||
Node *n = new Node(key, ext);
|
||||
_cur->childs.push_back(n);
|
||||
|
||||
_stack.push_back(_cur);
|
||||
_cur = n;
|
||||
}
|
||||
void ObjectEnd(const char *key, const Extend *ext) {
|
||||
(void)key;
|
||||
(void)ext;
|
||||
_cur = _stack.back();
|
||||
_stack.pop_back();
|
||||
}
|
||||
bool WriteNull(const char*key, const Extend *ext) {
|
||||
static std::string empty;
|
||||
return this->encode_string(key, empty, ext);
|
||||
}
|
||||
// string
|
||||
bool encode_string(const char*key, const std::string &val, const Extend *ext) {
|
||||
if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, string_quote(val)));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = val;
|
||||
} else if (!Extend::AliasFlag(ext, "xml", "cdata")) {
|
||||
Node *n = new Node(key);
|
||||
n->val = string_quote(val);
|
||||
_cur->childs.push_back(n);
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = "<![CDATA[" + val + "]]>";
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// bool
|
||||
bool encode_bool(const char*key, const bool &val, const Extend *ext) {
|
||||
std::string bval;
|
||||
if (val) {
|
||||
bval = "true";
|
||||
} else {
|
||||
bval = "false";
|
||||
}
|
||||
|
||||
if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, bval));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = bval;
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = bval;
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// integer
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_integer, bool>::type encode_number(const char*key, const T& val, const Extend *ext) {
|
||||
if (val==0 && Extend::OmitEmpty(ext)) {
|
||||
return false;
|
||||
} else if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, Util::itoa(val)));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = Util::itoa(val);
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = Util::itoa(val);
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// float
|
||||
template <class T>
|
||||
typename x_enable_if<numeric<T>::is_float, bool>::type encode_number(const char*key, const T &val, const Extend *ext) {
|
||||
if (val==0 && Extend::OmitEmpty(ext)) {
|
||||
return false;
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
os.precision(_decimalPlaces+1);
|
||||
os<<val;
|
||||
std::string fval = os.str();
|
||||
|
||||
if (Extend::Attribute(ext)) {
|
||||
_cur->attrs.push_back(Attr(key, fval));
|
||||
} else if (Extend::XmlContent(ext)) {
|
||||
_cur->val = fval;
|
||||
} else {
|
||||
Node *n = new Node(key);
|
||||
n->val = fval;
|
||||
_cur->childs.push_back(n);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// escape string
|
||||
static std::string string_quote(const std::string &val) {
|
||||
std::string ret;
|
||||
ret.reserve(val.length()*2);
|
||||
|
||||
for (size_t i=0; i<val.length(); ++i) {
|
||||
int c = (int)(val[i]) & 0xFF;
|
||||
switch (c) {
|
||||
case '<':
|
||||
ret += "<";
|
||||
break;
|
||||
case '>':
|
||||
ret += ">";
|
||||
break;
|
||||
case '&':
|
||||
ret += "&";
|
||||
break;
|
||||
case '\'':
|
||||
ret += "'";
|
||||
break;
|
||||
case '\"':
|
||||
ret += """;
|
||||
break;
|
||||
default:
|
||||
if(c >= ' ') {
|
||||
ret.push_back(val[i]);
|
||||
} else {
|
||||
ret += "\\x";
|
||||
unsigned char uch = (unsigned char)val[i];
|
||||
unsigned char h = (uch>>4)&0xf;
|
||||
unsigned char l = uch&0xf;
|
||||
if (h < 10) {
|
||||
ret.push_back(h+'0');
|
||||
} else {
|
||||
ret.push_back(h-10+'A');
|
||||
}
|
||||
if (l < 10) {
|
||||
ret.push_back(l+'0');
|
||||
} else {
|
||||
ret.push_back(l-10+'A');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void appendNode(const Node *nd, int depth) {
|
||||
bool indentEnd = true;
|
||||
|
||||
if (!nd->key.empty()) { // for array that without label
|
||||
indent(depth);
|
||||
_output.push_back('<');
|
||||
_output += nd->key;
|
||||
} else if (depth > 0) {
|
||||
depth--;
|
||||
}
|
||||
|
||||
// output attribute
|
||||
std::list<Attr>::const_iterator it;
|
||||
for (it=nd->attrs.begin(); it!=nd->attrs.end(); ++it) {
|
||||
_output.push_back(' ');
|
||||
_output += it->key;
|
||||
_output += "=\"";
|
||||
_output += it->val;
|
||||
_output.push_back('"');
|
||||
}
|
||||
|
||||
// no content, end object
|
||||
if (nd->val.empty() && nd->childs.size()==0) {
|
||||
if (!nd->key.empty()) {
|
||||
_output += "/>";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// key finished
|
||||
if (!nd->key.empty()) {
|
||||
_output.push_back('>');
|
||||
}
|
||||
if (!nd->val.empty()) {
|
||||
_output += nd->val;
|
||||
indentEnd = false;
|
||||
} else {
|
||||
std::list<Node*>::const_iterator it;
|
||||
for (it=nd->childs.begin(); it!=nd->childs.end(); ++it) {
|
||||
appendNode(*it, depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nd->key.empty()) {
|
||||
if (indentEnd) {
|
||||
indent(depth);
|
||||
}
|
||||
_output += "</";
|
||||
_output += nd->key;
|
||||
_output.push_back('>');
|
||||
}
|
||||
}
|
||||
void merge() {
|
||||
if (_output.length() > 0 || _root.childs.size()==0) {
|
||||
return;
|
||||
}
|
||||
|
||||
appendNode(_root.childs.front(), 0);
|
||||
}
|
||||
|
||||
void indent(int depth) {
|
||||
if (_indentCount < 0) {
|
||||
return;
|
||||
}
|
||||
_output.push_back('\n');
|
||||
if (_indentCount == 0) {
|
||||
return;
|
||||
}
|
||||
for (int i=0; i<depth*_indentCount; ++i) {
|
||||
_output.push_back(_indentChar);
|
||||
}
|
||||
}
|
||||
|
||||
Node _root;
|
||||
Node *_cur;
|
||||
std::list<Node*> _stack;
|
||||
|
||||
std::string _output;
|
||||
|
||||
int _indentCount;
|
||||
char _indentChar;
|
||||
|
||||
int _decimalPlaces;
|
||||
};
|
||||
|
||||
|
||||
class XmlEncoder {
|
||||
public:
|
||||
XmlEncoder() {
|
||||
indentCount = -1;
|
||||
indentChar = ' ';
|
||||
maxDecimalPlaces = 324;
|
||||
}
|
||||
XmlEncoder(int _indentCount, char _indentChar, int _maxDecimalPlaces = 324) { // compat
|
||||
indentCount = _indentCount;
|
||||
indentChar = _indentChar;
|
||||
maxDecimalPlaces = _maxDecimalPlaces;
|
||||
}
|
||||
|
||||
void SetMaxDecimalPlaces(int _maxDecimalPlaces) {
|
||||
maxDecimalPlaces = _maxDecimalPlaces;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string encode(const T&val, const std::string&root) {
|
||||
XmlWriter wr(indentCount, indentChar, maxDecimalPlaces);
|
||||
XEncoder<XmlWriter> en(wr);
|
||||
en.encode(root.c_str(), val, NULL);
|
||||
return wr.String();
|
||||
}
|
||||
|
||||
private:
|
||||
int indentCount;
|
||||
char indentChar;
|
||||
int maxDecimalPlaces;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
201
util/xpack/xpack.h
Executable file
201
util/xpack/xpack.h
Executable file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __X_PACK_H
|
||||
#define __X_PACK_H
|
||||
|
||||
#include "extend.h"
|
||||
#include "l1l2_expand.h"
|
||||
#include "traits.h"
|
||||
|
||||
/*
|
||||
work with X_PACK_N to expand macro
|
||||
struct MyX {
|
||||
int a;
|
||||
std::string b;
|
||||
double c;
|
||||
XPACK(A(a,"_id"), O(b,c));
|
||||
};
|
||||
|
||||
macro expand order:
|
||||
XPACK(A(a,"_id"), O(b,c))
|
||||
--> X_PACK_N(X_PACK_L1, X_PACK_L1_DECODE, , A(a, "_id"), O(b,c))
|
||||
--> X_PACK_L1_2(X_PACK_L1_DECODE, A(a, "_id"), O(b,c))
|
||||
--> X_PACK_L1_DECODE(A(a, "_id")) X_PACK_L1_DECODE(O(b,c))
|
||||
--> X_PACK_L1_DECODE_A(a, "_id") X_PACK_L1_DECODE_O(b,c)
|
||||
--> X_PACK_ACT_DECODE_A(a, "_id") X_PACK_N2(X_PACK_L2, X_PACK_ACT_DECODE_O, b, c) // https://gcc.gnu.org/onlinedocs/cpp/Self-Referential-Macros.html so we need define X_PACK_N2. if use X_PACK_N preprocessor will treat is as Self-Referential-Macros
|
||||
--> X_PACK_ACT_DECODE_A(a, "_id") X_PACK_L2_2(X_PACK_ACT_DECODE_O, b, c)
|
||||
--> X_PACK_ACT_DECODE_A(a, "_id") X_PACK_ACT_DECODE_O(b) X_PACK_ACT_DECODE_O(c)
|
||||
--> // expand to convert code
|
||||
*/
|
||||
|
||||
// flag only work for this member
|
||||
#define X_EXPAND_FLAG_F(...) int __x_pack_flag = 0 X_PACK_N2(X_PACK_L2, X_PACK_ACT_FLAG, 0, __VA_ARGS__) ;
|
||||
#define X_PACK_ACT_FLAG(ARG, F) | X_PACK_FLAG_##F
|
||||
|
||||
/*
|
||||
X(F(x,y,z), member1, member2, ....)
|
||||
O same as X(F(0), member1, member2, ...)
|
||||
M same as X(F(M), member1, member2, ...)
|
||||
A Alias. A(member1, alias1, member2, alias2, ...)
|
||||
AF Alias with Flag. A(F(x,y,z), member1, alias1, member2, alias2 ...)
|
||||
I Inherit
|
||||
B bitfield
|
||||
*/
|
||||
|
||||
/////////////////////////// XPACK /////////////////////////////
|
||||
//=======DECODE
|
||||
#define X_PACK_L1_DECODE(x) { X_PACK_L1_DECODE_##x }
|
||||
//----
|
||||
#define X_PACK_L1_DECODE_X(FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_O, 0, __VA_ARGS__)
|
||||
#define X_PACK_L1_DECODE_E(FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_E, 0, __VA_ARGS__)
|
||||
#define X_PACK_L1_DECODE_B(FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_B, 0, __VA_ARGS__)
|
||||
#define X_PACK_L1_DECODE_AF(FLAG, ...) X_EXPAND_FLAG_##FLAG X_PACK_N2(X_PACK_L2_2, X_PACK_DECODE_ACT_A, 0, __VA_ARGS__) // extend define in ACTION
|
||||
//-----customer decoder---------
|
||||
#define X_PACK_L1_DECODE_C(CUSTOM, FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_C, CUSTOM, __VA_ARGS__)
|
||||
|
||||
#define X_PACK_L1_DECODE_O(...) X_PACK_L1_DECODE_X(F(0), __VA_ARGS__)
|
||||
#define X_PACK_L1_DECODE_M(...) X_PACK_L1_DECODE_X(F(M), __VA_ARGS__)
|
||||
#define X_PACK_L1_DECODE_A(...) X_PACK_L1_DECODE_AF(F(0), __VA_ARGS__)
|
||||
|
||||
#define X_PACK_L1_DECODE_I(...) X_PACK_N2(X_PACK_L2, X_PACK_DECODE_ACT_I, 0, __VA_ARGS__)
|
||||
//=======ENCODE
|
||||
#define X_PACK_L1_ENCODE(x) { X_PACK_L1_ENCODE_##x }
|
||||
//-----
|
||||
#define X_PACK_L1_ENCODE_X(FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_O, 0, __VA_ARGS__)
|
||||
#define X_PACK_L1_ENCODE_E(FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_E, 0, __VA_ARGS__)
|
||||
#define X_PACK_L1_ENCODE_B(FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_B, 0, __VA_ARGS__)
|
||||
#define X_PACK_L1_ENCODE_AF(FLAG, ...) X_EXPAND_FLAG_##FLAG X_PACK_N2(X_PACK_L2_2, X_PACK_ENCODE_ACT_A, 0, __VA_ARGS__) // extend define in ACTION
|
||||
#define X_PACK_L1_ENCODE_C(CUSTOM, FLAG, ...) X_EXPAND_FLAG_##FLAG xpack::Extend __x_pack_ext(__x_pack_flag, NULL); X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_C, CUSTOM, __VA_ARGS__)
|
||||
|
||||
#define X_PACK_L1_ENCODE_O(...) X_PACK_L1_ENCODE_X(F(0), __VA_ARGS__)
|
||||
#define X_PACK_L1_ENCODE_M(...) X_PACK_L1_ENCODE_X(F(M), __VA_ARGS__)
|
||||
#define X_PACK_L1_ENCODE_A(...) X_PACK_L1_ENCODE_AF(F(0), __VA_ARGS__)
|
||||
//-----
|
||||
#define X_PACK_L1_ENCODE_I(...) X_PACK_N2(X_PACK_L2, X_PACK_ENCODE_ACT_I, 0, __VA_ARGS__)
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ decode act ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#define X_PACK_DECODE_ACT_O(ARG, M) \
|
||||
__x_pack_ret |= __x_pack_obj.decode(#M, __x_pack_self.M, &__x_pack_ext);
|
||||
|
||||
#define X_PACK_DECODE_ACT_C(CUSTOM, M) \
|
||||
__x_pack_ret |= CUSTOM##_decode(__x_pack_obj, __x_pack_self, #M, __x_pack_self.M, &__x_pack_ext);
|
||||
|
||||
// enum for not support c++11
|
||||
#ifndef X_PACK_SUPPORT_CXX0X
|
||||
#define X_PACK_DECODE_ACT_E(ARG, M) \
|
||||
__x_pack_ret |= __x_pack_obj.decode(#M, *((int*)&__x_pack_self.M), &__x_pack_ext);
|
||||
#else
|
||||
#define X_PACK_DECODE_ACT_E X_PACK_DECODE_ACT_O
|
||||
#endif
|
||||
|
||||
#define X_PACK_DECODE_ACT_A(ARG, M, NAME) \
|
||||
{ \
|
||||
static xpack::Alias __x_pack_alias(#M, NAME); \
|
||||
xpack::Extend __x_pack_ext(__x_pack_flag, &__x_pack_alias); \
|
||||
const char *__new_name = __x_pack_alias.Name(__x_pack_obj.Name());\
|
||||
__x_pack_ret |= __x_pack_obj.decode(__new_name, __x_pack_self.M, &__x_pack_ext); \
|
||||
}
|
||||
|
||||
// Inheritance B::__x_pack_decode(__x_pack_obj)
|
||||
#define X_PACK_DECODE_ACT_I(ARG, P) \
|
||||
{ \
|
||||
xpack::Extend __x_pack_tmp_ext(0,NULL); __x_pack_tmp_ext.ctrl_flag |= X_PACK_CTRL_FLAG_INHERIT;\
|
||||
__x_pack_ret |= __x_pack_obj.decode(static_cast<P&>(__x_pack_self), &__x_pack_tmp_ext); \
|
||||
}
|
||||
|
||||
// bitfield, not support alias
|
||||
#define X_PACK_DECODE_ACT_B(ARG, B) \
|
||||
{ \
|
||||
x_pack_decltype(__x_pack_self.B) __x_pack_tmp = 0; \
|
||||
__x_pack_ret |= __x_pack_obj.decode(#B, __x_pack_tmp, &__x_pack_ext); \
|
||||
__x_pack_self.B = __x_pack_tmp;\
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~ encode act ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#define X_PACK_ENCODE_ACT_O(ARG, M) \
|
||||
__x_pack_ret |= __x_pack_obj.encode(#M, __x_pack_self.M, &__x_pack_ext);
|
||||
#define X_PACK_ENCODE_ACT_C(CUSTOM, M) \
|
||||
__x_pack_ret |= CUSTOM##_encode(__x_pack_obj, __x_pack_self, #M, __x_pack_self.M, &__x_pack_ext);
|
||||
|
||||
#ifndef X_PACK_SUPPORT_CXX0X
|
||||
#define X_PACK_ENCODE_ACT_E(ARG, M) \
|
||||
__x_pack_ret |= __x_pack_obj.encode(#M, (const int&)__x_pack_self.M, &__x_pack_ext);
|
||||
#else
|
||||
#define X_PACK_ENCODE_ACT_E X_PACK_ENCODE_ACT_O
|
||||
#endif
|
||||
|
||||
#define X_PACK_ENCODE_ACT_A(ARG, M, NAME) \
|
||||
{ \
|
||||
static xpack::Alias __x_pack_alias(#M, NAME); \
|
||||
xpack::Extend __x_pack_ext(__x_pack_flag, &__x_pack_alias); \
|
||||
const char *__new_name = __x_pack_alias.Name(__x_pack_obj.Name());\
|
||||
__x_pack_ret |= __x_pack_obj.encode(__new_name, __x_pack_self.M, &__x_pack_ext); \
|
||||
}
|
||||
|
||||
#define X_PACK_ENCODE_ACT_B(ARG, M) \
|
||||
__x_pack_obj.encode(#M, __x_pack_self.M, &__x_pack_ext);
|
||||
|
||||
#define X_PACK_ENCODE_ACT_I(ARG, P) \
|
||||
{ \
|
||||
xpack::Extend __x_pack_tmp_ext(0,NULL); __x_pack_tmp_ext.ctrl_flag |= X_PACK_CTRL_FLAG_INHERIT;\
|
||||
__x_pack_ret |= __x_pack_obj.encode(NULL, static_cast<const P&>(__x_pack_self), &__x_pack_tmp_ext); \
|
||||
}
|
||||
|
||||
|
||||
// for mark defined XPACK
|
||||
#define X_PACK_COMMON \
|
||||
public: \
|
||||
static bool const __x_pack_value = true;
|
||||
|
||||
// decode function
|
||||
#define X_PACK_DECODE_BEGIN \
|
||||
template<class __X_PACK_DOC, class __X_PACK_ME> \
|
||||
bool __x_pack_decode(__X_PACK_DOC& __x_pack_obj, __X_PACK_ME &__x_pack_self, const xpack::Extend *__x_pack_extp) {(void)__x_pack_extp; bool __x_pack_ret = false;
|
||||
|
||||
// encode function
|
||||
#define X_PACK_ENCODE_BEGIN \
|
||||
template <class __X_PACK_DOC, class __X_PACK_ME> \
|
||||
bool __x_pack_encode(__X_PACK_DOC& __x_pack_obj, const __X_PACK_ME &__x_pack_self, const xpack::Extend *__x_pack_extp) const {(void)__x_pack_extp; bool __x_pack_ret = false;
|
||||
|
||||
|
||||
// out decode function
|
||||
#define X_PACK_DECODE_BEGIN_OUT(NAME) \
|
||||
template<typename __X_PACK_DOC> \
|
||||
bool __x_pack_decode_out(__X_PACK_DOC& __x_pack_obj, NAME & __x_pack_self, const xpack::Extend *__x_pack_extp) {(void)__x_pack_extp; bool __x_pack_ret = false;
|
||||
|
||||
// out encode function
|
||||
#define X_PACK_ENCODE_BEGIN_OUT(NAME) \
|
||||
template <class __X_PACK_DOC> \
|
||||
bool __x_pack_encode_out(__X_PACK_DOC& __x_pack_obj, const NAME &__x_pack_self, const xpack::Extend *__x_pack_extp) {(void)__x_pack_extp; bool __x_pack_ret = false;
|
||||
|
||||
|
||||
#define XPACK(...) \
|
||||
X_PACK_COMMON \
|
||||
X_PACK_DECODE_BEGIN X_PACK_N(X_PACK_L1, X_PACK_L1_DECODE, __VA_ARGS__) return __x_pack_ret; } \
|
||||
X_PACK_ENCODE_BEGIN X_PACK_N(X_PACK_L1, X_PACK_L1_ENCODE, __VA_ARGS__) return __x_pack_ret; }
|
||||
|
||||
#define XPACK_OUT(NAME, ...) \
|
||||
namespace xpack { \
|
||||
template<> struct is_xpack_out<NAME> {static bool const value = true;}; \
|
||||
X_PACK_DECODE_BEGIN_OUT(NAME) X_PACK_N(X_PACK_L1, X_PACK_L1_DECODE, __VA_ARGS__) return __x_pack_ret; } \
|
||||
X_PACK_ENCODE_BEGIN_OUT(NAME) X_PACK_N(X_PACK_L1, X_PACK_L1_ENCODE, __VA_ARGS__) return __x_pack_ret; } \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
3
util/xpack/xpack.pri
Executable file
3
util/xpack/xpack.pri
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
INCLUDEPATH += $$PWD
|
||||
DEFINES += XPACK_SUPPORT_QT
|
||||
HEADERS += xpack.h
|
||||
48
util/xpack/yaml.h
Executable file
48
util/xpack/yaml.h
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Duowan Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __X_PACK_YAML_H
|
||||
#define __X_PACK_YAML_H
|
||||
|
||||
#include "yaml_decoder.h"
|
||||
#include "yaml_encoder.h"
|
||||
#include "xpack.h"
|
||||
|
||||
namespace xpack {
|
||||
|
||||
class yaml {
|
||||
public:
|
||||
template <class T>
|
||||
static void decode(const std::string &data, T &val) {
|
||||
YamlDecoder de;
|
||||
de.decode(data, val);
|
||||
}
|
||||
template <class T>
|
||||
static void decode_file(const std::string &file_name, T &val) {
|
||||
YamlDecoder de;
|
||||
de.decode_file(file_name, val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string encode(const T &val) {
|
||||
YamlEncoder en;
|
||||
return en.encode(val);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue