From b9b61802e0a069b87098e5c1ee3e2f04d5ad2ef9 Mon Sep 17 00:00:00 2001 From: sfja Date: Sun, 29 Mar 2026 15:46:36 +0200 Subject: [PATCH] add files --- include/json.h | 81 ++++++++++++++++ include/json.hpp | 70 ++++++++++++++ include/json_collections.h | 103 ++++++++++++++++++++ src/jq.c | 77 +++++++++++++++ src/json_cpp.cpp | 191 +++++++++++++++++++++++++++++++++++++ 5 files changed, 522 insertions(+) create mode 100644 include/json.h create mode 100644 include/json.hpp create mode 100644 include/json_collections.h create mode 100644 src/jq.c create mode 100644 src/json_cpp.cpp diff --git a/include/json.h b/include/json.h new file mode 100644 index 0000000..807511d --- /dev/null +++ b/include/json.h @@ -0,0 +1,81 @@ +#ifndef JSON_H +#define JSON_H + +#include "json_collections.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum json_type { + json_null = 1, + json_false = 2, + json_true = 3, + json_int, + json_float, + json_string, + json_array, + json_object, +}; + +struct json_value; + +struct json_value* json_new(enum json_type type); +void json_free(struct json_value* value); + +bool json_is(struct json_value const* value, enum json_type type); + +enum json_type json_get_type(struct json_value const* value); +bool json_get_bool(struct json_value const* value); +int64_t json_get_int(struct json_value const* value); +double json_get_float(struct json_value const* value); +const char* json_get_string(struct json_value const* value); + +void json_set_null(struct json_value** value); +void json_set_bool(struct json_value** value, bool val); +void json_set_int(struct json_value** value, int64_t val); +void json_set_float(struct json_value** value, double val); +void json_set_string(struct json_value* value, char* val); + +struct json_value* json_new_int(int64_t val); +struct json_value* json_new_float(double val); + +size_t json_array_count(struct json_value const* array); +struct json_value* json_idx(struct json_value* array, size_t idx); +struct json_value const* json_idx_const( + struct json_value const* array, size_t idx); +void json_push(struct json_value* array, struct json_value* value); + +struct json_value* json_key(struct json_value* object, const char* key); +struct json_value* json_key_sized( + struct json_value* object, const char* key, size_t key_size); +struct json_value const* json_key_hash_const( + struct json_value const* object, size_t hash); +void json_set( + struct json_value* object, const char* key, struct json_value* value); +void json_set_sized(struct json_value* object, + const char* key, + size_t key_size, + struct json_value* value); +void json_object_keys(struct json_value const* object, + struct hash_key_entry const** keys, + size_t* count); + +struct json_value* json_parse( + const char* text, size_t text_size, struct blockalloc* alloc); + +struct json_value* json_query(struct json_value* val, const char* query); + +typedef int JsonWriteCb(void* self, const char* data, size_t size); + +int json_stringify( + struct json_value const* node, JsonWriteCb write, void* self); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/json.hpp b/include/json.hpp new file mode 100644 index 0000000..0d9166d --- /dev/null +++ b/include/json.hpp @@ -0,0 +1,70 @@ +#ifndef JSON_HPP +#define JSON_HPP + +#include +#include +#include +#include +#include +#include + +namespace json { + +enum class Type { + Null = 1, + False = 2, + True = 3, + Int = 4, + Float = 5, + String = 6, + Array = 7, + Object = 8, +}; + +class Underlying; + +class Value { +public: + Value(const Value&) = delete; + Value(Value&&) = delete; + Value& operator=(const Value&) = delete; + Value& operator=(Value&&) = delete; + + explicit Value(std::unique_ptr underlying) + : m_underlying(std::move(underlying)) { }; + + ~Value() = default; + + auto is(Type type) const -> bool; + auto get_type() const -> Type; + auto get_bool() const -> bool; + auto get_int() const -> std::int64_t; + auto get_float() const -> double; + auto get_string() const -> std::string_view; + + void set_null(); + void set_bool(bool val); + void set_int(int64_t val); + void set_float(double val); + void set_string(std::string_view val); + + auto count() const -> std::size_t; + auto get(std::size_t idx) -> std::unique_ptr; + auto get(std::size_t idx) const -> std::unique_ptr; + void push(std::unique_ptr value); + + auto get(std::string_view key) -> std::unique_ptr; + auto get(std::string_view key) const -> std::unique_ptr; + void set(std::string_view key, std::unique_ptr value); + + auto query(const std::string& query) -> std::unique_ptr; + +private: + std::unique_ptr m_underlying; +}; + +auto parse(std::string_view text) -> std::unique_ptr; + +} + +#endif diff --git a/include/json_collections.h b/include/json_collections.h new file mode 100644 index 0000000..90d4f95 --- /dev/null +++ b/include/json_collections.h @@ -0,0 +1,103 @@ +#ifndef COLLECTIONS_H +#define COLLECTIONS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *array_push(void **data, + size_t *capacity, + size_t *count, + void const *elem, + size_t elem_size); + +void *array_insert_at(void **data, + size_t *capacity, + size_t *count, + size_t idx, + void const *elem, + size_t elem_size); + +struct smallarray { + union { + size_t smalldata[3]; + struct { + void **data; + size_t capacity; + size_t count; + }; + }; +}; + +void smallarray_construct(struct smallarray *a); +void smallarray_destroy(struct smallarray *a); +void smallarray_push(struct smallarray *a, void *value); +size_t smallarray_count(struct smallarray const *a); +void *smallarray_get(struct smallarray *a, size_t idx); +void const *smallarray_get_const(struct smallarray const *a, size_t idx); + +struct hash_entry { + uint64_t hash; + void *value; +}; + +#define bucket_capacity 16 + +struct hash_bucket { + struct hash_entry entries[bucket_capacity]; + size_t count; + uint64_t first_hash; + uint64_t last_hash; +}; + +struct hash_key_entry { + uint64_t hash; + char *value; +}; + +struct hashmap { + struct hash_bucket *buckets; + size_t buckets_capacity; + size_t buckets_count; + struct hash_key_entry *keys; + size_t keys_capacity; + size_t keys_count; +}; + +void hashmap_construct(struct hashmap *m); +void hashmap_destroy(struct hashmap *m); +void hashmap_set(struct hashmap *m, char const *key, void *value); +void hashmap_set_sized( + struct hashmap *m, char const *key, size_t key_size, void *value); +bool hashmap_has(struct hashmap *m, char const *key); +void *hashmap_get(struct hashmap *m, char const *key); +void *hashmap_get_sized(struct hashmap *m, char const *key, size_t key_size); +void *hashmap_get_hash(struct hashmap *m, size_t hash); +void const *hashmap_get_hash_const(struct hashmap const *m, size_t hash); +void hashmap_keys( + struct hashmap const *m, struct hash_key_entry const **keys, size_t *count); + +#define blockalloc_default_block 4096 + +struct blockalloc_block; + +struct blockalloc { + struct blockalloc_block *blocks; + size_t capacity; + size_t count; + size_t p; +}; + +void blockalloc_construct(struct blockalloc *a); +void blockalloc_destroy(struct blockalloc *a); +void *blockalloc_alloc(struct blockalloc *a, size_t size, size_t align); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/jq.c b/src/jq.c new file mode 100644 index 0000000..54e1f41 --- /dev/null +++ b/src/jq.c @@ -0,0 +1,77 @@ +#include "json_collections.h" +#include "json.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static int stringify_cb(void *self, char const *data, unsigned long size) +{ + (void)self; + fwrite(data, size, 1, stdout); + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + fprintf(stderr, "error: incorrect arguments\n"); + return EXIT_FAILURE; + } + char const *query = argv[1]; + char const *filename = argv[2]; + + FILE *file = fopen(filename, "r"); + if (!file) { + fprintf(stderr, + "error: could not open file (%s) \"%s\"\n", + strerror(errno), + filename); + return EXIT_FAILURE; + } + + fseek(file, 0, SEEK_END); + long ftell_result = ftell(file); + if (ftell_result < 0) { + fprintf(stderr, "error: could not tell (%s)\n", strerror(errno)); + return EXIT_FAILURE; + } + fseek(file, 0, SEEK_SET); + size_t file_size = (size_t)ftell_result; + char *text = malloc(file_size + 1); + + size_t bytes_read = fread(text, 1, file_size, file); + if (bytes_read != file_size) { + fprintf(stderr, + "error: could not read %ld/%ld (%s)\n", + bytes_read, + file_size, + strerror(errno)); + return EXIT_FAILURE; + } + fclose(file); + + struct blockalloc alloc = { 0 }; + blockalloc_construct(&alloc); + + struct json_value *parsed = json_parse(text, file_size, &alloc); + if (!parsed) { + fprintf(stderr, "something went wrong\n"); + return EXIT_FAILURE; + } + free(text); + + struct json_value *result = json_query(parsed, query); + if (!result) { + return EXIT_FAILURE; + } + json_stringify(result, stringify_cb, NULL); + fputc('\n', stdout); + + json_free(parsed); + blockalloc_destroy(&alloc); +} diff --git a/src/json_cpp.cpp b/src/json_cpp.cpp new file mode 100644 index 0000000..a9974f4 --- /dev/null +++ b/src/json_cpp.cpp @@ -0,0 +1,191 @@ +#include "json.h" +#include "json.hpp" +#include "json_collections.h" +#include +#include +#include +#include + +namespace json { + +class Underlying { +public: + virtual auto ptr() -> struct json_value*& = 0; + virtual auto ptr() const -> const struct json_value* const& = 0; + virtual auto alloc_ptr() -> struct blockalloc* = 0; + +private: +}; + +class ValuePtr final : public Underlying { +public: + explicit ValuePtr(struct blockalloc* alloc, struct json_value* value) + : m_alloc(alloc) + , m_value(value) { }; + + auto ptr() -> struct json_value*& override + { + return m_value; + } + auto ptr() const -> const struct json_value* const& override + { + return m_value; + } + + auto alloc_ptr() -> struct blockalloc* override + { + return m_alloc; + } + +private: + struct blockalloc* m_alloc; + struct json_value* m_value; +}; + +auto Value::is(Type type) const -> bool +{ + return json_is(m_underlying->ptr(), (enum json_type)type); +} + +auto Value::get_type() const -> Type +{ + return (Type)json_get_type(m_underlying->ptr()); +} +auto Value::get_bool() const -> bool +{ + return json_get_bool(m_underlying->ptr()); +} +auto Value::get_int() const -> std::int64_t +{ + return json_get_int(m_underlying->ptr()); +} +auto Value::get_float() const -> double +{ + return json_get_float(m_underlying->ptr()); +} +auto Value::get_string() const -> std::string_view +{ + return json_get_string(m_underlying->ptr()); +} + +void Value::set_null() +{ + json_set_null(&m_underlying->ptr()); +} +void Value::set_bool(bool val) +{ + json_set_bool(&m_underlying->ptr(), val); +} +void Value::set_int(int64_t val) +{ + json_set_int(&m_underlying->ptr(), val); +} +void Value::set_float(double val) +{ + json_set_float(&m_underlying->ptr(), val); +} +void Value::set_string(std::string_view val) +{ + char* own_str + = (char*)blockalloc_alloc(m_underlying->alloc_ptr(), val.size() + 1, 2); + std::strncpy(own_str, val.data(), val.size() + 1); + json_set_string(m_underlying->ptr(), own_str); +} + +auto Value::count() const -> std::size_t +{ + return json_array_count(m_underlying->ptr()); +} +auto Value::get(std::size_t idx) -> std::unique_ptr +{ + return std::make_unique(std::make_unique( + m_underlying->alloc_ptr(), json_idx(m_underlying->ptr(), idx))); +} +auto Value::get(std::size_t idx) const -> std::unique_ptr +{ + return std::make_unique(std::make_unique( + m_underlying->alloc_ptr(), json_idx(m_underlying->ptr(), idx))); +} +void Value::push(std::unique_ptr value) +{ + json_push(m_underlying->ptr(), value->m_underlying->ptr()); +} + +auto Value::get(std::string_view key) -> std::unique_ptr +{ + return std::make_unique( + std::make_unique(m_underlying->alloc_ptr(), + json_key_sized(m_underlying->ptr(), key.data(), key.size()))); +} +auto Value::get(std::string_view key) const -> std::unique_ptr +{ + return std::make_unique( + std::make_unique(m_underlying->alloc_ptr(), + json_key_sized(m_underlying->ptr(), key.data(), key.size()))); +} +void Value::set(std::string_view key, std::unique_ptr value) +{ + json_set_sized(m_underlying->ptr(), + key.data(), + key.size(), + value->m_underlying->ptr()); +} + +auto Value::query(const std::string& query) -> std::unique_ptr +{ + return std::make_unique( + std::make_unique(m_underlying->alloc_ptr(), + json_query(m_underlying->ptr(), query.c_str()))); +} + +class Doc final : public Underlying { +public: + explicit Doc() + { + blockalloc_construct(&m_alloc); + } + + ~Doc() + { + blockalloc_destroy(&m_alloc); + if (m_value) { + json_free(m_value); + } + } + + int parse(std::string_view text) + { + m_value = json_parse(text.data(), text.size(), &m_alloc); + if (!m_value) + return 1; + return 0; + } + + auto ptr() -> struct json_value*& override + { + return m_value; + } + auto ptr() const -> const struct json_value* const& override + { + return m_value; + } + + auto alloc_ptr() -> struct blockalloc* override + { + return &m_alloc; + } + +private: + struct blockalloc m_alloc; + struct json_value* m_value = nullptr; +}; + +auto parse(std::string_view text) -> std::unique_ptr +{ + auto doc = std::make_unique(); + if (doc->parse(text) != 0) + return nullptr; + return std::make_unique(std::move(doc)); +} + +}