Thinger.io Client Library for ARM mbed platform. This is a generic library that provides a base class that can be used to other develop hardware specific libraries.
Fork of ThingerClient by
thinger/pson.h
- Committer:
- alvarolb
- Date:
- 2015-12-26
- Revision:
- 4:de51256455f7
- Parent:
- 0:b75d784c7c1a
File content as of revision 4:de51256455f7:
// The MIT License (MIT) // // Copyright (c) 2015 THINGER LTD // Author: alvarolb@gmail.com (Alvaro Luis Bustamante) // // 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. #ifndef PSON_HPP #define PSON_HPP #include <stdint.h> #include <string.h> #include <math.h> #include <stdlib.h> namespace protoson { class memory_allocator{ public: virtual void *allocate(size_t size) = 0; virtual void deallocate(void *) = 0; }; template<size_t buffer_size> class circular_memory_allocator : public memory_allocator{ private: uint8_t buffer_[buffer_size]; size_t index_; public: circular_memory_allocator() : index_(0) { } virtual void *allocate(size_t size) { if (index_ + size > buffer_size) { index_ = 0; } void *position = &buffer_[index_]; index_ += size; return position; } virtual void deallocate(void *) { } }; class dynamic_memory_allocator : public memory_allocator{ public: virtual void *allocate(size_t size) { return malloc(size); } virtual void deallocate(void *ptr) { free(ptr); } }; extern memory_allocator& pool; } inline void* operator new(size_t sz, protoson::memory_allocator& a) { return a.allocate(sz); } inline void operator delete(void* p, protoson::memory_allocator& a) { a.deallocate(p); } template<class T> void destroy(T* p, protoson::memory_allocator& a) { if (p) { p->~T(); a.deallocate(p); } } namespace protoson { enum pb_wire_type{ varint = 0, fixed_64 = 1, length_delimited = 2, fixed_32 = 5, pson_type = 6 }; template<class T> class pson_container { struct list_item{ T item_; list_item* next_; }; public: class iterator{ public: iterator(list_item *current) : current(current) { } private: list_item * current; public: bool next(){ if(current==NULL) return false; current = current->next_; return true; } bool has_next(){ return current!=NULL && current->next_!=NULL; } bool valid(){ return current!=NULL; } T& item(){ return current->item_; } }; private: list_item* item_; public: iterator begin() const{ return iterator(item_); } pson_container() : item_(NULL) { } ~pson_container(){ clear(); } size_t size() const{ size_t size = 0; list_item* current = item_; while(current!=NULL){ current = current->next_; size++; } return size; } T* operator[](size_t index){ list_item* current = item_; size_t current_index = 0; while(current!=NULL){ if(current_index==index){ return ¤t->item_; } current = current->next_; current_index++; } return NULL; } void clear(){ list_item* current = item_; while(current!=NULL){ list_item* next = current->next_; destroy(current, pool); current = next; } item_ = NULL; } T& create_item(){ list_item* new_list_item = new(pool) list_item(); if(item_==NULL){ item_ = new_list_item; } else{ list_item * last = item_; while(last->next_!=NULL) last = last->next_; last->next_ = new_list_item; } return new_list_item->item_; } }; class pson_object; class pson_array; class pson { public: enum field_type { null_field = 0, varint_field = 1, svarint_field = 2, float_field = 3, double_field = 4, true_field = 5, false_field = 6, zero_field = 7, one_field = 8, string_field = 9, empty_string = 10, bytes_field = 11, empty_bytes = 12, object_field = 13, array_field = 14, empty = 15, // a message tag is encoded in a 128-base varint [1-bit][3-bit wire type][4-bit field] // we have up to 4 bits (0-15) for encoding fields in the first byte }; bool is_boolean() const{ return field_type_ == true_field || field_type_ == false_field; } bool is_string() const{ return field_type_ == string_field; } bool is_bytes() const{ return field_type_ == bytes_field; } bool is_number() const{ return field_type_ == varint_field || field_type_ == svarint_field || field_type_ == float_field || field_type_ == double_field || field_type_ == zero_field || field_type_ == one_field; } bool is_object() const{ return field_type_ == object_field; } bool is_array() const{ return field_type_ == array_field; } bool is_null() const{ return field_type_ == null_field; } bool is_empty() const{ return field_type_ == empty; } pson() : value_(NULL), field_type_(empty) { } template<class T> pson(T value) : value_(NULL), field_type_(empty){ *this = value; } ~pson(){ if(field_type_==object_field){ destroy((pson_object *) value_, pool); }else if(field_type_==array_field) { destroy((pson_array *) value_, pool); }else{ pool.deallocate(value_); } } template<class T> void operator=(T value) { if(value==0){ field_type_ = zero_field; }else if(value==1) { field_type_ = one_field; }else{ field_type_ = value>0 ? varint_field : svarint_field; uint64_t uint_value = value>0 ? value : -value; value_ = pool.allocate(pson::get_varint_size(uint_value)); pb_encode_varint(uint_value); } } void operator=(bool value){ field_type_ = value ? true_field : false_field; } void operator=(float value) { if(value==(int32_t)value){ *this = (int32_t) value; }else{ field_type_ = float_field; set(value); } } void operator=(double value) { if(value==(int64_t)value) { *this = (int64_t) value; }else if(fabs(value-(float)value)<=0.00001){ field_type_ = float_field; set((float)value); }else{ field_type_ = double_field; set(value); } } void operator=(const char *str) { size_t str_size = strlen(str); if(str_size==0){ field_type_ = empty_string; }else{ field_type_ = string_field; memcpy(allocate(str_size+1), str, str_size+1); } } void set_bytes(const void* bytes, size_t size) { if(size>0){ size_t varint_size = get_varint_size(size); value_ = pool.allocate(varint_size+size); pb_encode_varint(size); memcpy(((uint8_t*)value_)+varint_size, bytes, size); field_type_ = bytes_field; }else{ field_type_ = empty_bytes; } } bool get_bytes(const void*& bytes, size_t& size){ switch(field_type_){ case bytes_field: size = pb_decode_varint(); bytes = (uint8_t*) value_ + get_varint_size(size); return true; case empty: field_type_ = empty_bytes; default: return false; } } void* allocate(size_t size){ value_ = pool.allocate(size); return value_; } operator pson_object &(); operator pson_array &(); pson & operator[](const char *name); operator const char *() { switch(field_type_){ case string_field: return (const char*) value_; case empty: field_type_ = empty_string; default: return ""; } } operator bool(){ switch(field_type_){ case zero_field: case false_field: return false; case one_field: case true_field: return true; case empty: field_type_ = false_field; default: return 0; } } operator char(){ return get_value<char>(); } operator unsigned char(){ return get_value<unsigned char>(); } operator short(){ return get_value<short>(); } operator unsigned short(){ return get_value<unsigned short>(); } operator int(){ return get_value<int>(); } operator unsigned int(){ return get_value<int>(); } operator long(){ return get_value<long>(); } operator unsigned long(){ return get_value<unsigned long>(); } operator float(){ return get_value<float>(); } operator double(){ return get_value<double>(); } template<class T> operator T() { return get_value<T>(); } template<class T> T get_value(){ switch(field_type_){ case one_field: case true_field: return 1; case float_field: return *(float*)value_; case double_field: return *(double*)value_; case varint_field: return pb_decode_varint(); case svarint_field: return -pb_decode_varint(); case empty: field_type_ = zero_field; default: return 0; } } void* get_value(){ return value_; } void set_value(void* value){ value_ = value; } field_type get_type() const{ return field_type_; } void set_null(){ field_type_ = null_field; } void set_type(field_type type){ field_type_ = type; } uint8_t get_varint_size(uint64_t value) const{ uint8_t size = 1; while(value>>=7) size++; return size; } void pb_encode_varint(uint64_t value) const { uint8_t count = 0; do { uint8_t byte = (uint8_t)(value & 0x7F); value >>= 7; if(value) byte |= 0x80; ((uint8_t*)value_)[count] = byte; count++; }while(value); } uint64_t pb_decode_varint() const { if(value_==NULL) return 0; uint64_t value = 0; uint8_t pos = 0; uint8_t byte = 0; do{ byte = ((uint8_t*)value_)[pos]; value |= (uint64_t)(byte&0x7F) << pos*7; pos++; }while(byte>=0x80); return value; } private: void* value_; field_type field_type_; template<class T> void set(T value) { memcpy(allocate(sizeof(T)), &value, sizeof(T)); } }; class pson_pair{ private: char* name_; pson value_; public: pson_pair() : name_(NULL){ } ~pson_pair(){ destroy(name_, pool); } void set_name(const char *name) { size_t name_size = strlen(name) + 1; memcpy(allocate_name(name_size), name, name_size); } char* allocate_name(size_t size){ name_ = (char*)pool.allocate(size); return name_; } pson& value(){ return value_; } char* name() const{ return name_; } }; class pson_object : public pson_container<pson_pair> { public: pson &operator[](const char *name) { for(iterator it=begin(); it.valid(); it.next()){ if(strcmp(it.item().name(), name)==0){ return it.item().value(); } } pson_pair & pair = create_item(); pair.set_name(name); return pair.value(); }; }; class pson_array : public pson_container<pson> { public: template<class T> pson_array& add(T item_value){ create_item() = item_value; return *this; } }; inline pson::operator pson_object &() { if (field_type_ != object_field) { value_ = new(pool) pson_object; field_type_ = object_field; } return *((pson_object *)value_); } inline pson::operator pson_array &() { if (field_type_ != array_field) { value_ = new(pool) pson_array; field_type_ = array_field; } return *((pson_array *)value_); } inline pson &pson::operator[](const char *name) { return ((pson_object &) *this)[name]; } //////////////////////////// /////// PSON_DECODER /////// //////////////////////////// class pson_decoder { protected: size_t read_; virtual bool read(void* buffer, size_t size){ read_+=size; return true; } public: pson_decoder() : read_(0) { } void reset(){ read_ = 0; } size_t bytes_read(){ return read_; } bool pb_decode_tag(pb_wire_type& wire_type, uint32_t& field_number) { uint32_t temp = pb_decode_varint32(); wire_type = (pb_wire_type)(temp & 0x07); field_number = temp >> 3; return true; } uint32_t pb_decode_varint32() { uint32_t varint = 0; if(try_pb_decode_varint32(varint)){ return varint; } return 0; } bool try_pb_decode_varint32(uint32_t& varint){ varint = 0; uint8_t byte; uint8_t bit_pos = 0; do{ if(!read(&byte, 1) || bit_pos>=32){ return false; } varint |= (uint32_t)(byte&0x7F) << bit_pos; bit_pos += 7; }while(byte>=0x80); return true; } uint64_t pb_decode_varint64() { uint64_t varint = 0; uint8_t byte; uint8_t bit_pos = 0; do{ if(!read(&byte, 1) || bit_pos>=64){ return varint; } varint |= (uint32_t)(byte&0x7F) << bit_pos; bit_pos += 7; }while(byte>=0x80); return varint; } bool pb_skip(size_t size){ uint8_t byte; bool success = true; for(size_t i=0; i<size; i++){ success &= read(&byte, 1); } return success; } bool pb_skip_varint(){ uint8_t byte; bool success = true; do{ success &= read(&byte, 1); }while(byte>0x80); return success; } bool pb_read_string(char *str, size_t size){ bool success = read(str, size); str[size]=0; return success; } bool pb_read_varint(pson& value) { uint8_t temp[10]; uint8_t byte=0; uint8_t bytes_read=0; do{ if(!read(&byte, 1)) return false; temp[bytes_read] = byte; bytes_read++; }while(byte>=0x80); memcpy(value.allocate(bytes_read), temp, bytes_read); return true; } public: void decode(pson_object & object, size_t size){ size_t start_read = bytes_read(); while(size-(bytes_read()-start_read)>0){ decode(object.create_item()); } } void decode(pson_array & array, size_t size){ size_t start_read = bytes_read(); while(size-(bytes_read()-start_read)>0){ decode(array.create_item()); } } void decode(pson_pair & pair){ uint32_t name_size = pb_decode_varint32(); pb_read_string(pair.allocate_name(name_size+1), name_size); decode(pair.value()); } void decode(pson& value) { uint32_t field_number; pb_wire_type wire_type; pb_decode_tag(wire_type, field_number); value.set_type((pson::field_type)field_number); if(wire_type==length_delimited){ uint32_t size = pb_decode_varint32(); switch(field_number){ case pson::string_field: pb_read_string((char*)value.allocate(size + 1), size); break; case pson::bytes_field: { uint8_t varint_size = value.get_varint_size(size); read((char*)value.allocate(size + varint_size) + varint_size, size); value.pb_encode_varint(size); } break; case pson::object_field: value.set_value(new (pool) pson_object); decode(*(pson_object *)value.get_value(), size); break; case pson::array_field: value.set_value(new (pool) pson_array); decode(*(pson_array *)value.get_value(), size); break; default: pb_skip(size); break; } }else { switch (field_number) { case pson::svarint_field: case pson::varint_field: pb_read_varint(value); break; case pson::float_field: read(value.allocate(4), 4); break; case pson::double_field: read(value.allocate(8), 8); break; default: break; } } } }; //////////////////////////// /////// PSON_ENCODER /////// //////////////////////////// class pson_encoder { protected: size_t written_; virtual void write(const void* buffer, size_t size){ written_+=size; } public: pson_encoder() : written_(0) { } void reset(){ written_ = 0; } size_t bytes_written(){ return written_; } void pb_encode_tag(pb_wire_type wire_type, uint32_t field_number){ uint64_t tag = ((uint64_t)field_number << 3) | wire_type; pb_encode_varint(tag); } void pb_encode_varint(uint32_t field, uint64_t value) { pb_encode_tag(varint, field); pb_encode_varint(value); } uint8_t pb_write_varint(void * buffer) { uint8_t byte=0; uint8_t bytes_written=0; do{ byte = *((uint8_t*)buffer + bytes_written); bytes_written++; }while(byte>=0x80); write(buffer, bytes_written); return bytes_written; } void pb_encode_varint(uint64_t value) { do { uint8_t byte = (uint8_t)(value & 0x7F); value >>= 7; if(value>0) byte |= 0x80; write(&byte, 1); }while(value>0); } void pb_encode_string(const char* str, uint32_t field_number){ pb_encode_tag(length_delimited, field_number); pb_encode_string(str); } void pb_encode_string(const char* str){ size_t string_size = strlen(str); pb_encode_varint(string_size); write(str, string_size); } template<class T> void pb_encode_submessage(T& element, uint32_t field_number) { pb_encode_tag(length_delimited, field_number); pson_encoder sink; sink.encode(element); pb_encode_varint(sink.bytes_written()); encode(element); } void pb_encode_fixed32(void* value){ write(value, 4); } void pb_encode_fixed64(void* value){ write(value, 8); } void pb_encode_fixed32(uint32_t field, void*value) { pb_encode_tag(fixed_32, field); pb_encode_fixed32(value); } void pb_encode_fixed64(uint32_t field, void*value) { pb_encode_tag(fixed_64, field); pb_encode_fixed64(value); } public: void encode(pson_object & object){ pson_container<pson_pair>::iterator it = object.begin(); while(it.valid()){ encode(it.item()); it.next(); } } void encode(pson_array & array){ pson_container<pson>::iterator it = array.begin(); while(it.valid()){ encode(it.item()); it.next(); } } void encode(pson_pair & pair){ pb_encode_string(pair.name()); encode(pair.value()); } void encode(pson & value) { switch (value.get_type()) { case pson::string_field: pb_encode_string((const char*)value.get_value(), pson::string_field); break; case pson::bytes_field: pb_encode_tag(length_delimited, pson::bytes_field); write(((const char *) value.get_value()) + pb_write_varint(value.get_value()), value.pb_decode_varint()); break; case pson::svarint_field: case pson::varint_field: pb_encode_tag(varint, value.get_type()); pb_write_varint(value.get_value()); break; case pson::float_field: pb_encode_fixed32(pson::float_field, value.get_value()); break; case pson::double_field: pb_encode_fixed64(pson::double_field, value.get_value()); break; case pson::object_field: pb_encode_submessage(*(pson_object *) value.get_value(), pson::object_field); break; case pson::array_field: pb_encode_submessage(*(pson_array *) value.get_value(), pson::array_field); break; default: pb_encode_tag(varint, value.get_type()); break; } } }; } #endif