├── .gitignore ├── LICENSE ├── README.md ├── gemmaJSON.nimble ├── src ├── gemmaJSON.nim └── gemmaJSON │ ├── compile.nim │ ├── gemmasimdjsonc.cpp │ ├── gemmasimdjsonc.h │ ├── simdjson.cpp │ └── simdjson.h └── tests ├── config.nims └── test_core.nim /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files with no extention: 2 | * 3 | !*/ 4 | !*.* 5 | 6 | # normal ignores: 7 | *.exe 8 | nimcache 9 | .DS_Store 10 | *.out 11 | # idk why I have to add this, cause it's in my global gitignore 12 | .vim 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 aingel.art 190 | 191 | Copyright 2021 TeskaLabs Ltd 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![gemmaJSONlogo](https://github.com/sainttttt/gemmaJSON/assets/58609876/836b0495-6d6d-476d-b124-fa7d9979f00f) 2 | gemmaJSON - simdjson bindings for Nim 3 | 4 | `nimble install gemmaJSON` 5 | 6 | 7 | ## Benchmarks 8 | 9 | Test was for deserialization of reddit comment json dumps, checking if the entry was from a specific subreddit 10 | 11 | ``` 12 | name ................. min time avg time std dv times 13 | sainttttt/gemmaJSON .. 13.291 s 13.386 s ±0.110 x15 14 | treeform/jsony ....... 28.280 s 28.659 s ±0.366 x15 15 | nim std/json ......... 72.095 s 73.678 s ±1.436 x15 16 | ``` 17 | 18 | ## Usage 19 | 20 | ```nim 21 | var jsonObj = parseGemmajsonObj("""{"cat": {"a": ["woof", ["meow"], 2]}}""") 22 | 23 | echo jsonObj.getStr("/cat/a/0") 24 | # woof 25 | 26 | echo jsonObj.getStr("/cat/a/1/0") 27 | # meow 28 | 29 | echo $jsonObj["cat"]["a"][0] 30 | # woof 31 | 32 | echo $jsonObj 33 | # {"cat":{"a":["woof",["meow"],2]}} 34 | 35 | var j = jsonObj.toJsonNode.pretty 36 | echo j.pretty 37 | 38 | # { 39 | # "cat": { 40 | # "a": [ 41 | # "woof", 42 | # [ 43 | # "meow" 44 | # ], 45 | # 2 46 | # ] 47 | # } 48 | # } 49 | 50 | for e in jsonObj.getElement("/cat/a"): 51 | echo $e 52 | 53 | # woof 54 | # ["meow"] 55 | # 2 56 | 57 | ``` 58 | -------------------------------------------------------------------------------- /gemmaJSON.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.1.0" 4 | author = "saint" 5 | description = "json parsing library based on bindings of simdjson" 6 | license = "Apache-2.0" 7 | srcDir = "src" 8 | 9 | 10 | # Dependencies 11 | 12 | requires "nim >= 2.0.0" 13 | -------------------------------------------------------------------------------- /src/gemmaJSON.nim: -------------------------------------------------------------------------------- 1 | import system/ctypes 2 | include ./gemmaJSON/compile 3 | import std/json 4 | 5 | type gemmaJSON = pointer 6 | 7 | type 8 | GemmaNodeType* = enum 9 | Unknown, String, Int, Array, Object 10 | 11 | type gemmaNode* = object 12 | nodeType: GemmaNodeType 13 | json: gemmaJSON 14 | dataString: string 15 | dataInt: int 16 | 17 | proc newParser(): pointer {.importc: "gemmasimdjson_parser_new", 18 | header: "gemmasimdjsonc.h".} 19 | proc elementSizeOf(): csize_t {.importc: "gemmasimdjson_element_sizeof", 20 | header: "gemmasimdjsonc.h".} 21 | proc arraySizeOf(array: gemmaJSON): csize_t {. importc: "gemmasimdjson_array_size", 22 | header: "gemmasimdjsonc.h".} 23 | proc parserParse( parser: pointer, element: pointer, 24 | data: cstring, len: csize_t): bool {.importc: "gemmasimdjson_parser_parse", 25 | header: "gemmasimdjsonc.h".} 26 | proc getStr(attrname: cstring, attrlen: csize_t, 27 | element: pointer, output: var cstring, 28 | outputlen: var csize_t): bool {.importc: "gemmasimdjson_element_get_str", 29 | header: "gemmasimdjsonc.h".} 30 | proc gemmasimdjson_element_get_int64_t(attrname: cstring, attrlen: csize_t, 31 | e: pointer, output: ptr cint) {.importc: "gemmasimdjson_element_get_int64_t", 32 | header: "gemmasimdjsonc.h".} 33 | proc gemmasimdjson_element_get(attrname: cstring, attrlen: csize_t, 34 | e: pointer, output_element: pointer): bool {.importc: "gemmasimdjson_element_get", 35 | header: "gemmasimdjsonc.h".} 36 | 37 | proc gemmasimdjson_element_get_type(attrname: cstring, attrlen: csize_t, 38 | e: pointer): char {.importc: "gemmasimdjson_element_get_type", 39 | header: "gemmasimdjsonc.h".} 40 | 41 | proc gemmasimdjson_minify(element: pointer): cstring {.importc: "gemmasimdjson_minify", 42 | header: "gemmasimdjsonc.h".} 43 | 44 | proc parseGemmaJSON*(s: string): gemmaNode = 45 | var parser = newParser() 46 | var gemmaJSON = alloc0(elementSizeof()) 47 | var success = parserParse(parser, gemmaJSON, s, s.len.c_size_t) 48 | # var type = gemmasimdjson_element_get_type("", cast[csize_t](0), gemmaJSON) 49 | return gemmaNode(json: cast[gemmaJSON](gemmaJSON)) 50 | 51 | proc getStr*(g: gemmaJSON, attr: string): string = 52 | var outstr: cstring 53 | var outstrsize: csize_t 54 | var error = getStr(attr.cstring, attr.len.csize_t, g, outstr, outstrsize) 55 | return $outstr 56 | 57 | 58 | proc getElement*(n: gemmaNode, attr: string): gemmaNode = 59 | var gemmaJSON = alloc0(elementSizeof()) 60 | var node = gemmaNode(json: cast[gemmaJSON](gemmaJSON)) 61 | var error = gemmasimdjson_element_get(attr.cstring, attr.len.csize_t, n.json, node.json) 62 | return node 63 | 64 | proc getInt*(g: gemmaJSON, attr: string): int = 65 | var outInt: cint 66 | gemmasimdjson_element_get_int64_t(attr.cstring, attr.len.csize_t, g, addr outInt) 67 | return outInt.int 68 | 69 | proc type*(n: var gemmaNode): GemmaNodeType = 70 | if n.nodeType == GemmaNodeType.Unknown: 71 | var nodeType = gemmasimdjson_element_get_type("", cast[csize_t](0), n.json) 72 | if nodeType == 'i': 73 | n.nodeType = GemmaNodeType.Int 74 | elif nodeType == 's': 75 | n.nodeType = GemmaNodeType.String 76 | elif nodeType == 'A': 77 | n.nodeType = GemmaNodeType.Array 78 | elif nodeType == 'O': 79 | n.nodeType = GemmaNodeType.Object 80 | 81 | return n.nodeType 82 | 83 | proc type*(n: gemmaNode): GemmaNodeType = 84 | var nodeType = gemmasimdjson_element_get_type("", cast[csize_t](0), n.json) 85 | if nodeType == 'i': 86 | return GemmaNodeType.Int 87 | elif nodeType == 's': 88 | return GemmaNodeType.String 89 | elif nodeType == 'A': 90 | return GemmaNodeType.Array 91 | elif nodeType == 'O': 92 | return GemmaNodeType.Object 93 | 94 | 95 | proc getInt*(n: gemmaNode, attr: string = ""): int = 96 | return n.json.getInt(attr) 97 | 98 | proc getStr*(n: gemmaNode, attr: string = ""): string = 99 | return n.json.getStr(attr) 100 | 101 | proc `[]`*(n: gemmaNode, attr: string): gemmaNode = 102 | return n.getElement(&"/{attr}") 103 | 104 | proc `[]`*(n: gemmaNode, index: int): gemmaNode = 105 | return n.getElement(&"/{index}") 106 | 107 | proc `$`*(n: gemmaNode): string = 108 | var minify = gemmasimdjson_minify(n.json) 109 | return $minify 110 | 111 | proc minify(n: gemmaNode): string = 112 | var outString: cstring 113 | var bufferSize = 10.csize_t 114 | var minify = gemmasimdjson_minify(n.json) 115 | return $minify 116 | 117 | proc toJsonNode*(n: gemmaNode): JsonNode = 118 | return parseJSON($n) 119 | 120 | iterator items*(n: gemmaNode): gemmaNode = 121 | if n.type != GemmaNodeType.Array: 122 | yield gemmaNode() 123 | 124 | var numItems = n.json.arraySizeOf.int 125 | for i in 0..numItems - 1: 126 | var indexStr = &"/{i}" 127 | yield n.getElement(indexStr) 128 | -------------------------------------------------------------------------------- /src/gemmaJSON/compile.nim: -------------------------------------------------------------------------------- 1 | import std/os 2 | import std/strformat 3 | import std/compilesettings 4 | 5 | proc sh(cmd: string; dir: string= ""): void = 6 | ## Executes the given shell command and writes the output to console. 7 | ## Same as the nimscript version, but usable at compile time in static blocks. 8 | ## Runs the command from `dir` when specified. 9 | when defined(windows): {.warning: "running `sh -c` commands on Windows has not been tested".} 10 | var command :string 11 | echo cmd 12 | if dir != "": command = &"cd {dir}; " & cmd 13 | else: command = cmd 14 | discard gorgeEx(&"sh -c \"{$command}\"").output 15 | 16 | proc doesExist (path: string): bool = 17 | let command = fmt"[ -f {path} ] && echo 1 || echo 2" 18 | let output = gorgeEx(&"sh -c \"{command}\"").output 19 | return output == "1" 20 | 21 | const cacheDir = compilesettings.querySetting(nimcacheDir) 22 | const outDir = compilesettings.querySetting(outDir) 23 | 24 | const curSrcPath = currentSourcePath.parentDir 25 | 26 | # {.passL: &"-L{trgDir}/ -lgemmaJSON".} 27 | 28 | static: 29 | sh(&"""mkdir -p {cacheDir}""") 30 | when defined(linux): 31 | sh(&"""g++ -fpic -c -O3 {curSrcPath}/gemmasimdjsonc.cpp {curSrcPath}/simdjson.cpp """, cacheDir) 32 | elif defined(macosx): 33 | if not doesExist(fmt"{cacheDir}/simdjson.o"): 34 | echo "building simdjson" 35 | sh(&"""clang++ -c -O3 {curSrcPath}/gemmasimdjsonc.cpp {curSrcPath}/simdjson.cpp -std=c++11""", cacheDir) 36 | 37 | # sh(&"""cp {cacheDir}/libgemmaJSON.so {outDir}/""") 38 | 39 | {.passC: &"-I{curSrcPath}/" .} 40 | {.passL: &"{cacheDir}/gemmasimdjsonc.o {cacheDir}/simdjson.o".} 41 | 42 | when defined(linux): 43 | {.passL: "-lstdc++" .} 44 | elif defined(macosx): 45 | {.passL: "-lc++" .} 46 | -------------------------------------------------------------------------------- /src/gemmaJSON/gemmasimdjsonc.cpp: -------------------------------------------------------------------------------- 1 | #include "simdjson.h" 2 | #include "gemmasimdjsonc.h" 3 | 4 | void * gemmasimdjson_parser_new(void) { 5 | simdjson::dom::parser * parser = new simdjson::dom::parser(); 6 | void * p = static_cast(parser); 7 | return p; 8 | } 9 | 10 | void gemmasimdjson_parser_del(void * p) { 11 | assert(p != NULL); 12 | simdjson::dom::parser * parser = static_cast(p); 13 | delete parser; 14 | } 15 | 16 | 17 | const size_t gemmasimdjson_element_sizeof(void) { 18 | return sizeof(simdjson::dom::element); 19 | } 20 | 21 | bool gemmasimdjson_parser_parse(void * p, void * memory, char * data, size_t datalen) { 22 | simdjson::dom::parser * parser = static_cast(p); 23 | /* static_cast(static_castdata */ 24 | 25 | try { 26 | // Initialize the element at the memory provided by a caller 27 | // See: https://www.geeksforgeeks.org/placement-new-operator-cpp/ 28 | // `memory` is a pointer to a pre-allocated memory space with >= gemmasimdjson_element_sizeof() bytes 29 | simdjson::dom::element * element = new(memory) simdjson::dom::element(); 30 | 31 | // Parse the JSON 32 | auto err = parser->parse( 33 | static_cast(static_cast(data)), datalen, 34 | true // Create a copy if needed (TODO: this may be optimized eventually to save data copy) 35 | ).get(*element); 36 | 37 | if (err) { 38 | // Likely syntax error in JSON 39 | return true; 40 | } 41 | 42 | } catch (const std::bad_alloc& e) { 43 | // Error when allocating memory 44 | return true; 45 | } 46 | catch (...) { 47 | return true; 48 | } 49 | // No error 50 | return false; 51 | } 52 | 53 | 54 | bool gemmasimdjson_element_get_str(const char * attrname, size_t attrlen, void * e, char ** output, size_t * outputlen) { 55 | simdjson::dom::element * element = static_cast(e); 56 | std::string_view pointer = std::string_view(attrname, attrlen); 57 | 58 | std::string_view result; 59 | 60 | auto err = element->at_pointer(pointer).get(result); 61 | if (err) { 62 | return true; 63 | } 64 | 65 | *output = (char *)result.data(); 66 | *outputlen = result.size(); 67 | return false; 68 | } 69 | 70 | bool gemmasimdjson_element_get_int64_t(const char * attrname, size_t attrlen, void * e, int64_t * output) { 71 | 72 | simdjson::dom::element * element = static_cast(e); 73 | std::string_view pointer = std::string_view(attrname, attrlen); 74 | 75 | int64_t result; 76 | auto err = element->at_pointer(pointer).get(result); 77 | if (err) { 78 | return true; 79 | } 80 | 81 | *output = result; 82 | return false; 83 | } 84 | 85 | bool gemmasimdjson_element_get_uint64_t(const char * attrname, size_t attrlen, void * e, uint64_t * output) { 86 | simdjson::dom::element * element = static_cast(e); 87 | std::string_view pointer = std::string_view(attrname, attrlen); 88 | 89 | uint64_t result; 90 | auto err = element->at_pointer(pointer).get(result); 91 | if (err) { 92 | return true; 93 | } 94 | 95 | *output = result; 96 | return false; 97 | } 98 | 99 | bool gemmasimdjson_element_get_bool(const char * attrname, size_t attrlen, void * e, bool * output) { 100 | simdjson::dom::element * element = static_cast(e); 101 | std::string_view pointer = std::string_view(attrname, attrlen); 102 | 103 | bool result; 104 | auto err = element->at_pointer(pointer).get(result); 105 | if (err) { 106 | return true; 107 | } 108 | 109 | *output = result; 110 | return false; 111 | } 112 | 113 | bool gemmasimdjson_element_get_double(const char * attrname, size_t attrlen, void * e, double * output) { 114 | simdjson::dom::element * element = static_cast(e); 115 | std::string_view pointer = std::string_view(attrname, attrlen); 116 | 117 | double result; 118 | auto err = element->at_pointer(pointer).get(result); 119 | if (err) { 120 | return true; 121 | } 122 | 123 | *output = result; 124 | return false; 125 | } 126 | 127 | char gemmasimdjson_element_get_type(const char * attrname, size_t attrlen, void * e) { 128 | simdjson::dom::element * element = static_cast(e); 129 | std::string_view pointer = std::string_view(attrname, attrlen); 130 | 131 | simdjson::dom::element_type result; 132 | auto err = element->at_pointer(pointer).type().get(result); 133 | if (err) { 134 | return '\0'; 135 | } 136 | 137 | switch (result) { 138 | case simdjson::dom::element_type::INT64: return 'i'; 139 | case simdjson::dom::element_type::UINT64: return 'u'; 140 | case simdjson::dom::element_type::STRING: return 's'; 141 | case simdjson::dom::element_type::DOUBLE: return 'f'; 142 | case simdjson::dom::element_type::BOOL: return 'B'; 143 | case simdjson::dom::element_type::ARRAY: return 'A'; 144 | case simdjson::dom::element_type::OBJECT: return 'O'; 145 | case simdjson::dom::element_type::NULL_VALUE: return 'N'; 146 | } 147 | 148 | return '?'; 149 | } 150 | 151 | bool gemmasimdjson_element_get(const char * attrname, size_t attrlen, void * e, void * output_element) { 152 | simdjson::dom::element * element = static_cast(e); 153 | std::string_view pointer = std::string_view(attrname, attrlen); 154 | 155 | simdjson::dom::element * sub_element = new(output_element) simdjson::dom::element(); 156 | 157 | auto err = element->at_pointer(pointer).get(*sub_element); 158 | if (err) { 159 | return true; 160 | } 161 | 162 | return false; 163 | 164 | } 165 | 166 | size_t gemmasimdjson_array_size(void * e) { 167 | simdjson::dom::array *array = static_cast(e); 168 | auto size = array->size(); 169 | return size; 170 | } 171 | 172 | // This is here for an unit test 173 | int gemmasimdjson_parser_test() { 174 | simdjson::dom::parser parser; 175 | simdjson::dom::object object; 176 | 177 | const char * jsond = R"({"key":"value"} )"; 178 | const size_t jsond_len = std::strlen(jsond); 179 | 180 | auto error = parser.parse(jsond, jsond_len).get(object); 181 | if (error) { 182 | return -1; 183 | } 184 | 185 | return 0; 186 | } 187 | 188 | char * gemmasimdjson_minify(void * e) { 189 | simdjson::dom::element * element = static_cast(e); 190 | std::string json_string = simdjson::minify(*element); 191 | char *buf = (char *)malloc(json_string.size()); 192 | std::strcpy(buf, json_string.c_str()); 193 | printf("%s\n", (char *)json_string.c_str()); 194 | return buf; 195 | } 196 | -------------------------------------------------------------------------------- /src/gemmaJSON/gemmasimdjsonc.h: -------------------------------------------------------------------------------- 1 | #ifndef CYSIMDJSONAPI_H 2 | #define CYSIMDJSONAPI_H 3 | 4 | // This is API for C (not C++) level 5 | // This header has to be C compliant 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | void * gemmasimdjson_parser_new(void); 17 | void gemmasimdjson_parser_del(void * parser); 18 | 19 | const size_t gemmasimdjson_element_sizeof(void); 20 | 21 | // `element` is a pointer with pre-allocated buffer of the size=gemmasimdjson_element_sizeof() 22 | bool gemmasimdjson_parser_parse(void * p, void * memory, char * data, size_t datalen); 23 | 24 | bool gemmasimdjson_element_get_str(const char * attrname, size_t attrlen, void * element, char ** output, size_t * outputlen); 25 | bool gemmasimdjson_element_get_int64_t(const char * attrname, size_t attrlen, void * element, int64_t * output); 26 | bool gemmasimdjson_element_get_uint64_t(const char * attrname, size_t attrlen, void * element, uint64_t * output); 27 | bool gemmasimdjson_element_get_bool(const char * attrname, size_t attrlen, void * element, bool * output); 28 | bool gemmasimdjson_element_get_double(const char * attrname, size_t attrlen, void * element, double * output); 29 | 30 | char gemmasimdjson_element_get_type(const char * attrname, size_t attrlen, void * element); 31 | bool gemmasimdjson_element_get(const char * attrname, size_t attrlen, void * element, void * output_element); 32 | 33 | int gemmasimdjson_parser_test(void); 34 | 35 | size_t gemmasimdjson_array_size(void * e); 36 | 37 | // Export element `e` as JSON into the "buffer" and returns the exported JSON size. 38 | // If the "buffer_size" is too small, returns 0; 39 | char * gemmasimdjson_minify(void * e); 40 | 41 | #endif 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /tests/config.nims: -------------------------------------------------------------------------------- 1 | --path:"../src" 2 | -------------------------------------------------------------------------------- /tests/test_core.nim: -------------------------------------------------------------------------------- 1 | discard """ 2 | """ 3 | import gemmaJSON 4 | import std/json 5 | 6 | var strToParse = """{ 7 | "cat": { 8 | "a": [ 9 | "woof", 10 | [ 11 | "meow" 12 | ], 13 | 2 14 | ] 15 | } 16 | }""" 17 | 18 | var jsonObj = parseGemmaJSON(strToParse) 19 | assert jsonObj.type == GemmaNodeType.Object 20 | 21 | var el = jsonObj.getElement("/cat/a") 22 | assert el.type == GemmaNodeType.Array 23 | 24 | var i = 0 25 | 26 | var targetTypes = @[GemmaNodeType.String, 27 | GemmaNodeType.Array, 28 | GemmaNodeType.Int] 29 | # test iterator 30 | for e in el: 31 | assert e.type == targetTypes[i] 32 | i += 1 33 | 34 | assert jsonObj.getStr("/cat/a/0") == "woof" 35 | assert jsonObj.getStr("/cat/a/1/0") == "meow" 36 | assert jsonObj.getInt("/cat/a/2") == 2 37 | 38 | assert jsonObj["cat"]["a"][0].getStr == "woof" 39 | assert $jsonObj["cat"]["a"][0] == "\"woof\"" 40 | 41 | assert $jsonObj == """{"cat":{"a":["woof",["meow"],2]}}""" 42 | 43 | assert jsonObj.toJsonNode.pretty == parseJSON(strToParse).pretty 44 | echo jsonObj.toJsonNode.pretty 45 | --------------------------------------------------------------------------------