add files
This commit is contained in:
parent
c9d06ad189
commit
b9b61802e0
81
include/json.h
Normal file
81
include/json.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef JSON_H
|
||||||
|
#define JSON_H
|
||||||
|
|
||||||
|
#include "json_collections.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
||||||
70
include/json.hpp
Normal file
70
include/json.hpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef JSON_HPP
|
||||||
|
#define JSON_HPP
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
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> 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<Value>;
|
||||||
|
auto get(std::size_t idx) const -> std::unique_ptr<const Value>;
|
||||||
|
void push(std::unique_ptr<Value> value);
|
||||||
|
|
||||||
|
auto get(std::string_view key) -> std::unique_ptr<Value>;
|
||||||
|
auto get(std::string_view key) const -> std::unique_ptr<const Value>;
|
||||||
|
void set(std::string_view key, std::unique_ptr<Value> value);
|
||||||
|
|
||||||
|
auto query(const std::string& query) -> std::unique_ptr<Value>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Underlying> m_underlying;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto parse(std::string_view text) -> std::unique_ptr<Value>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
103
include/json_collections.h
Normal file
103
include/json_collections.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#ifndef COLLECTIONS_H
|
||||||
|
#define COLLECTIONS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
||||||
77
src/jq.c
Normal file
77
src/jq.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "json_collections.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
191
src/json_cpp.cpp
Normal file
191
src/json_cpp.cpp
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include "json.h"
|
||||||
|
#include "json.hpp"
|
||||||
|
#include "json_collections.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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<Value>
|
||||||
|
{
|
||||||
|
return std::make_unique<Value>(std::make_unique<ValuePtr>(
|
||||||
|
m_underlying->alloc_ptr(), json_idx(m_underlying->ptr(), idx)));
|
||||||
|
}
|
||||||
|
auto Value::get(std::size_t idx) const -> std::unique_ptr<const Value>
|
||||||
|
{
|
||||||
|
return std::make_unique<Value>(std::make_unique<ValuePtr>(
|
||||||
|
m_underlying->alloc_ptr(), json_idx(m_underlying->ptr(), idx)));
|
||||||
|
}
|
||||||
|
void Value::push(std::unique_ptr<Value> value)
|
||||||
|
{
|
||||||
|
json_push(m_underlying->ptr(), value->m_underlying->ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Value::get(std::string_view key) -> std::unique_ptr<Value>
|
||||||
|
{
|
||||||
|
return std::make_unique<Value>(
|
||||||
|
std::make_unique<ValuePtr>(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<const Value>
|
||||||
|
{
|
||||||
|
return std::make_unique<Value>(
|
||||||
|
std::make_unique<ValuePtr>(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> 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<Value>
|
||||||
|
{
|
||||||
|
return std::make_unique<Value>(
|
||||||
|
std::make_unique<ValuePtr>(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<Value>
|
||||||
|
{
|
||||||
|
auto doc = std::make_unique<Doc>();
|
||||||
|
if (doc->parse(text) != 0)
|
||||||
|
return nullptr;
|
||||||
|
return std::make_unique<Value>(std::move(doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user