序列化反序列化库 RedCell
jopen 13年前
<div id="p_fullcontent" class="detail"> <p>一个序列化反序列化库,提供 C++ 和 Python 两种语言的版本。</p> <p>功能和JSON类似,但是具有极高的空间和时间效率。<br /> <br /> <span style="font-weight:bold;">项目地址</span>:<a href="/misc/goto?guid=4958194706534809042" target="_blank">http://code.google.com/p/redcell/</a></p> <h1>简介</h1> <p>Redcell serializes nested key-value tables into compact binary byte-sequences, and deserializes them back. These operations and the binary format are now supported in both C++ and Python. </p> <p>A table uses unsigned integers as keys, and a value can be: </p> <ul> <li>A nil value </li> <li>A signed integer from 8bit to 64bit </li> <li>A floating-point number of single (32bit) or double (64bit) precision </li> <li>A string of single-byte characters of any length, allowing all sorts of binany contents </li> <li>Another table </li> </ul> <p>The binary format is compact and efficient, in which numbers are compressed and continuous key sequences are omitted as well, plus that each flag indicating the element type occupies just half a byte. </p> <p>Redcell can be compared with JSON, Protocol Buffers, and similar products, and can typically be used in network transfer, or object persistence, etc. </p> <h1><a name="C++_Usage"></a>C++ 用法</h1> <p>The C++ library of redcell consists only of header files, so any compilation before usage is not needed. Just one header needs to be included manually: </p> <pre class="prettyprint"><span class="com">#include</span><span class="pln"> </span><span class="str">"redcell.hpp"</span></pre> <p>And its contents is like the formal definitions with comments below, the order of which is not by the source code, but just for ease to understand. </p> <pre class="brush:cpp; toolbar: true; auto-links: false;">namespace redcell { /* Key and value type definitions. A key is an unsigned integer, and a value, besides the types defined below, can also be "nil" (not defined by value) or be another Table. */ typedef std::size_t Key; typedef long long Integer; typedef double Real; typedef std::string String; /* Constants returned when inquiring the type of a certain value. see the methods Table::type and Variant::type. */ enum { NIL = 0x0, INTEGER = 0x1, REAL = 0x2, STRING = 0x3, TABLE = 0x4, }; /* Table is the basic unit of redcell data structure. You manage data built with nested tables, serialize them to binary bytes, and deserialize them back. */ struct Table { /* Table is something like a pointer, holding real data below using a reference-counting mechanism. So do not make reference loops. There are only default-formed ctor/dtor and assignment operator. */ Table(); Table(const Table &rhs); ~Table(); Table &operator =(const Table &rhs); /* Accessing an element in the table, the parameter indicated its position. The type of each value will be decided by which access method is called the latest. If this key does not exist in the table, a new element will be inserted. */ Integer &i(const Key key); Real &r(const Key key); String &s(const Key key); Table &t(const Key key); /* This group of method do read-only access to an element, changing neither its type nor its value, nor its existence. If the calling type differs from the value stored, a TypeError will be thrown. And if the key does not exist, a KeyError will be thrown as well. */ const Integer &ci(const Key key) const; const Real &cr(const Key key) const; const String &cs(const Key key) const; const Table &ct(const Key key) const; /* This group of method is just for convenience, doing read-only access when on a constant Table object. */ const Integer &i(const Key key) const { return ci(key); } const Real &r(const Key key) const { return cr(key); } const String &s(const Key key) const { return cs(key); } const Table &t(const Key key) const { return ct(key); } /* Assign a 'nil' value to a certain key. */ void nil(const Key key); /* Delete an element from the table. */ void del(const Key key); /* Get the type of the value indicated by a key, the return value will be an enumeration value defined above. */ char type(const Key key) const; /* The arrow operator is overloaded to access the real data below the pointer. The class TableImpl is derived from a std::map, and is expected to be used as that. This is typically for Table iteration, and that four typedef's is also for convenience for this. see below for detail of TableImpl. */ TableImpl *operator ->() const; typedef TableImpl::iterator iterator; typedef TableImpl::const_iterator const_iterator; typedef TableImpl::reverse_iterator reverse_iterator; typedef TableImpl::const_reverse_iterator const_reverse_iterator; /* Merge another Table onto this Table. That means all key-value pairs in 'patch' will be inserted into this Table, overwriting all existing values, if any. Except that, if an incoming value and the corresponding local value are both Table, the former will be merged onto the latter using this method as well, rather than to overwrite it. */ void merge(const Table &patch); }; /* Variant is the low-level class for holding one value in the Table. Generally, you will iterate a Table like this: for (Table::iterator i = t->begin(); i != t->end; ++i) { // do something with i->second, which is an object of type 'Variant &'. } */ struct TableImpl: public TableMap {}; typedef std::map<Key, Variant> TableMap; struct Variant { /* Assign the type and the value of another Variant to this. */ Variant &operator =(const Variant &rhs); /* These groups of access methods below are just the per-Variant versions of these in class Table, accessing the sole value this Variant holds. */ Integer &i(); Real &r(); String &s(); Table &t(); const Integer &ci() const; const Real &cr() const; const String &cs() const; const Table &ct() const; const Integer &i() const { return ci(); } const Real &r() const { return cr(); } const String &s() const { return cs(); } const Table &t() const { return ct(); } void nil(); char type() const; }; /* This dumps the contents of a nested Table tree recursively into a human-readable string, mainly for debugging reasons. */ String dump(const Table &tab); /* These functions serializes a nested Table tree into the redcell binary format, to various destinations. Which can be an iterator (like what the STL algorithms did), a C++ standard stream, or a string. */ template <typename Iterator> void iteratorPack(const Table &tab, Iterator begin); void streamPack(const Table &tab, std::ostream &os); String pack(const Table &tab); /* These functions deserializes a byte sequence in the redcell binary format back to a nested Table tree, from various sources just like above. If the source format is wrong, a MarshalError will be thrown. */ template <typename Iterator> Table iteratorUnpack(Iterator begin, Iterator end); Table streamUnpack(std::istream &is); Table unpack(const String str); /* All exceptions redcell throws, all mentioned above. */ struct Error: public std::runtime_error {}; struct KeyError: public Error {}; struct TypeError: public Error {}; struct MarshalError: public Error {}; }</pre> <p></p> <h1><a name="Python_Usage"></a>Python 用法<br /> </h1> <p>To set up into Python, run the scripts redcell provided: </p> <pre class="prettyprint"><span class="pun">./</span><span class="pln">setup</span><span class="pun">.</span><span class="pln">py build sudo </span><span class="pun">./</span><span class="pln">setup</span><span class="pun">.</span><span class="pln">py install</span></pre> <p>Then, in Python source, you can import the package and deal with tables. In Python, tables are just native dict's with some constraints: The keys and values must be of the types supported by redcell, i.e. keys must be non-negative integers, and values must be an int, long, float, str, another dict, or None for 'nil'. You can do things just like below: </p> <pre class="brush:python; toolbar: true; auto-links: false;">import redcell t = {1: 1234, 4: 'hello', 8: {55: 3.1416}} print redcell.dump(t) raw = redcell.pack(t) u = redcell.unpack(raw) redcell.merge(u, {1: 4321, 8: {66: 2.7183}})</pre> <p></p> </div>