Implement custom pool API

Now it's poosible to use any custom pool allocation, i.e
preallocated pools or dymamic allocation on fly.
This commit is contained in:
Vladislav Grishenko 2018-11-10 23:37:33 +05:00
parent 9052ef2473
commit b3804dcf50
4 changed files with 170 additions and 12 deletions

121
example-03.c Normal file
View File

@ -0,0 +1,121 @@
/*
<https://github.com/rafagafe/tiny-json>
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2016-2018 Rafa Garcia <rafagarcia77@gmail.com>.
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.
*/
/*
* In this example the JSON library is used to analyze an object that some
* properties are expected.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tiny-json.h"
typedef struct jsonStaticPool_s {
json_t mem[32];
unsigned int nextFree;
jsonPool_t pool;
} jsonStaticPool_t;
static json_t* poolInit( jsonPool_t* pool ) {
jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool);
spool->nextFree = 1;
return &spool->mem[0];
}
static json_t* poolNew( jsonPool_t* pool ) {
jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool);
if ( spool->nextFree >= sizeof spool->mem / sizeof spool->mem[0] ) return 0;
return &spool->mem[spool->nextFree++];
}
/* Parser a json string. */
int main( void ) {
char str[] = "{\n"
"\t\"firstName\": \"Bidhan\",\n"
"\t\"lastName\": \"Chatterjee\",\n"
"\t\"age\": 40,\n"
"\t\"address\": {\n"
"\t\t\"streetAddress\": \"144 J B Hazra Road\",\n"
"\t\t\"city\": \"Burdwan\",\n"
"\t\t\"state\": \"Paschimbanga\",\n"
"\t\t\"postalCode\": \"713102\"\n"
"\t},\n"
"\t\"phoneList\": [\n"
"\t\t{ \"type\": \"personal\", \"number\": \"09832209761\" },\n"
"\t\t{ \"type\": \"fax\", \"number\": \"91-342-2567692\" }\n"
"\t]\n"
"}\n";
puts( str );
jsonStaticPool_t spool = { .pool = { .init = poolInit, .new = poolNew } };
json_t const* json = json_create_pool( str, &spool.pool );
if ( !json ) {
puts("Error json create.");
return EXIT_FAILURE;
}
json_t const* firstName = json_getProperty( json, "firstName" );
if ( !firstName || JSON_TEXT != json_getType( firstName ) ) {
puts("Error, the first name property is not found.");
return EXIT_FAILURE;
}
char const* firstNameVal = json_getValue( firstName );
printf( "Fist Name: %s.\n", firstNameVal );
char const* lastName = json_getPropertyValue( json, "lastName" );
if ( !lastName ) {
puts("Error, the last name property is not found.");
return EXIT_FAILURE;
}
printf( "Last Name: %s.\n", lastName );
json_t const* age = json_getProperty( json, "age" );
if ( !age || JSON_INTEGER != json_getType( age ) ) {
puts("Error, the age property is not found.");
return EXIT_FAILURE;
}
int const ageVal = (int)json_getInteger( age );
printf( "Age: %d.\n", ageVal );
json_t const* phoneList = json_getProperty( json, "phoneList" );
if ( !phoneList || JSON_ARRAY != json_getType( phoneList ) ) {
puts("Error, the phone list property is not found.");
return EXIT_FAILURE;
}
json_t const* phone;
for( phone = json_getChild( phoneList ); phone != 0; phone = json_getSibling( phone ) ) {
if ( JSON_OBJ == json_getType( phone ) ) {
char const* phoneNumber = json_getPropertyValue( phone, "number" );
if ( phoneNumber ) printf( "Number: %s.\n", phoneNumber );
}
}
return EXIT_SUCCESS;
}

View File

@ -1,6 +1,6 @@
build: example-01.exe example-02.exe
build: example-01.exe example-02.exe example-03.exe
clean:
rm -rf *.o
@ -17,6 +17,9 @@ example-01.exe: example-01.o tiny-json.o
example-02.exe: example-02.o tiny-json.o
gcc -std=c99 -Wall -o example-02.exe example-02.o tiny-json.o
example-03.exe: example-03.o tiny-json.o
gcc -std=c99 -Wall -o example-03.exe example-03.o tiny-json.o
test.exe: tests.o tiny-json.o
gcc -std=c99 -Wall -o test.exe tests.o tiny-json.o
@ -29,5 +32,8 @@ example-01.o: example-01.c tiny-json.h
example-02.o: example-02.c tiny-json.h
gcc -std=c99 -Wall -c example-02.c
example-03.o: example-03.c tiny-json.h
gcc -std=c99 -Wall -c example-03.c
tests.o: tests.c tiny-json.h
gcc -std=c99 -Wall -c tests.c

View File

@ -32,11 +32,12 @@
#include "tiny-json.h"
/** Structure to handle a heap of JSON properties. */
typedef struct jsonPool_s {
typedef struct jsonStaticPool_s {
json_t* const mem; /**< Pointer to array of json properties. */
unsigned int const qty; /**< Length of the array of json properties. */
unsigned int nextFree; /**< The index of the next free json property. */
} jsonPool_t;
jsonPool_t pool;
} jsonStaticPool_t;
/* Search a property by its name in a JSON object. */
json_t const* json_getProperty( json_t const* obj, char const* property ) {
@ -66,19 +67,27 @@ static char* setToNull( char* ch );
static bool isEndOfPrimitive( char ch );
/* Parse a string to get a json. */
json_t const* json_create( char* str, json_t mem[], unsigned int qty ) {
json_t const* json_create_pool( char* str, jsonPool_t* pool ) {
char* ptr = goBlank( str );
if ( !ptr || *ptr != '{' ) return 0;
jsonPool_t pool = { .mem = mem, .qty = qty };
json_t* obj = poolInit( &pool );
json_t* obj = pool->init( pool );
obj->name = 0;
obj->sibling = 0;
obj->u.c.child = 0;
ptr = objValue( ptr, obj, &pool );
ptr = objValue( ptr, obj, pool );
if ( !ptr ) return 0;
return obj;
}
/* Parse a string to get a json. */
json_t const* json_create( char* str, json_t mem[], unsigned int qty ) {
jsonStaticPool_t spool = {
.mem = mem, .qty = qty,
.pool = { .init = poolInit, .new = poolNew }
};
return json_create_pool( str, &spool.pool );
}
/** Get a special character with its escape character. Examples:
* 'b' -> '\b', 'n' -> '\n', 't' -> '\t'
* @param ch The escape character.
@ -335,7 +344,7 @@ static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ) {
++ptr;
continue;
}
json_t* property = poolNew( pool );
json_t* property = pool->new( pool );
if ( !property ) return 0;
if( obj->type != JSON_ARRAY ) {
if ( *ptr != '\"' ) return 0;
@ -374,8 +383,9 @@ static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ) {
* @param pool The handler of the pool.
* @return a instance of a json. */
static json_t* poolInit( jsonPool_t* pool ) {
pool->nextFree = 1;
return &pool->mem[0];
jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool);
spool->nextFree = 1;
return &spool->mem[0];
}
/** Create an instance of a json from a pool.
@ -383,8 +393,9 @@ static json_t* poolInit( jsonPool_t* pool ) {
* @retval The handler of the new instance if success.
* @retval Null pointer if the pool was empty. */
static json_t* poolNew( jsonPool_t* pool ) {
if ( pool->nextFree >= pool->qty ) return 0;
return &pool->mem[pool->nextFree++];
jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool);
if ( spool->nextFree >= spool->qty ) return 0;
return &spool->mem[spool->nextFree++];
}
/** Checks whether an character belongs to set.

View File

@ -34,10 +34,15 @@
extern "C" {
#endif
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define json_container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
((type *)(__mptr - offsetof(type, member))); })
/** @defgroup tinyJson Tiny JSON parser.
* @{ */
@ -61,6 +66,13 @@ typedef struct json_s {
jsonType_t type;
} json_t;
/** Structure to handle a heap of JSON properties. */
typedef struct jsonPool_s jsonPool_t;
typedef struct jsonPool_s {
json_t* (*init) ( jsonPool_t* pool );
json_t* (*new) ( jsonPool_t* pool );
} jsonPool_t;
/** Parse a string to get a json.
* @param str String pointer with a JSON object. It will be modified.
* @param mem Array of json properties to allocate.
@ -70,6 +82,14 @@ typedef struct json_s {
* This property is always unnamed and its type is JSON_OBJ. */
json_t const* json_create( char* str, json_t mem[], unsigned int qty );
/** Parse a string to get a json.
* @param str String pointer with a JSON object. It will be modified.
* @param pool Custom json pool pointer.
* @retval Null pointer if any was wrong in the parse process.
* @retval If the parser process was successfully a valid handler of a json.
* This property is always unnamed and its type is JSON_OBJ. */
json_t const* json_create_pool( char* str, jsonPool_t *pool );
/** Get the name of a json property.
* @param json A valid handler of a json property.
* @retval Pointer to null-terminated if property has name.