1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
1.x vs 2.x
==========
Allocation
----------
Allocation mechanisms has been revised. All objects are still allocated from a private storage (called heap),
but now the heap serves properly aligned memory chunks. Implementation of the heap is (hopefully) platform
independent, so all ``ARM_COMPLIANT`` checks has been removed. Some details work differently on 32/64-bit
machines, this distinction seems inevitable. Allocation related code has been moved to ``util/utilmem*.c`` files.
[There are actually 3 different allocators - **heap**, **stock**, and **pool** - each of which has 4 variants
for 1, 2, 4 and 8 bytes alignment. So far ``pplib`` uses only the **heap**, but I want to have this part
in a single place for a while. More notes about allocators in ``utilmemallc.h``.]
``pplib`` uses two heaps:
* bytes heap - providing 2-bytes aligned memory chunks for byte data
* structures heap - providing 8-bytes aligned chunks for all structures
2-bytes alignment of byte data is caused by implementation details / limits, ``pplib`` doesn't make a use of it
(could be unaligned as well). All the structures are stored in 8-bytes aligned chunks on both 32 and 64-bit machines
(in some structures we use ``double`` and ``int64_t``, which generally needs 8-bytes).
Strings And Names
-----------------
So far, both ``ppname`` and ``ppstring`` were aliases to ``char *`` with an extra structure hidden just below
the data address. The idea was to make a string or name usable whenever chars array can, at the cost of some
pointers trickery. Both names and strings keep an information about pdf-encoded data, as well as plain bytes data.
I implemented this feature once ``pplib 1.0`` was almost done, and to avoid a revolution, I made that with yet
another trick. This all was dirty and caused lots of alignment issues.
Now ``ppstring`` and ``ppname`` are **structures**, keeping data and size members, pretty much like ``pparray``::
struct ppname {
ppbyte *data;
size_t size;
ppname *alterego;
int flags;
};
struct ppstring {
ppbyte *data;
size_t size;
ppstring *alterego;
int flags;
};
Data member is a pointer to (2-bytes aligned) bytes array -- ``ppbyte *``. ``ppbyte`` is an alias to ``char``.
``pplib`` makes no assumptions about ``ppbyte`` signedness. [I'd prefer to have ``uint8_t``, but better
keep that in sync with ``ppdict_get_*`` suite, which accepts ``char *``. Using ``"string literals"``
with ``ppdict_get`` function is the most common case, I guess.]
``ppname_size()`` and ``ppstring_size() `` now have
trivial ``ppname_data()`` and ``ppstring_data()`` counterparts::
#define ppname_size(name) ((name)->size)
#define ppname_data(name) ((name)->data)
#define ppstring_size(string) ((string)->size)
#define ppstring_data(string) ((string)->data)
Switching between encoded / decoded variants is made via explicit ``alterego`` member. If encoded and decoded forms
are identical, then ``self->alfterego == self`` (never NULL). Helper functions for that::
PPAPI ppname * ppname_decoded (ppname *name);
PPAPI ppname * ppname_encoded (ppname *name);
PPAPI ppbyte * ppname_decoded_data (ppname *name);
PPAPI ppbyte * ppname_encoded_data (ppname *name);
PPAPI ppstring * ppstring_decoded (ppstring *string);
PPAPI ppstring * ppstring_encoded (ppstring *string);
PPAPI ppbyte * ppstring_decoded_data (ppstring *string);
PPAPI ppbyte * ppstring_encoded_data (ppstring *string);
Since ``ppname`` and ``ppstring`` are now structures, all API functions returning name/string or taking name/string
as an argument, now take **a pointer to name/string**. Watch out for ``ppdict_get_*`` functions suite. They still accept
``const char *`` key as an argument, but ``ppname`` type can no longer be used there::
ppname key;
ppdict_get_something(dict, key); // wrong
ppdict_get_something(dict, key.data); // ok
ppname *pkey;
ppdict_get_something(dict, (const char *)pkey); // wrong
ppdict_get_something(dict, pkey->data); // ok
Consequently, functions / macros that used pointer to ``ppname`` (``ppdict_first()`` / ``ppdict_next()``),
now needs ``ppname **pname``.
Cleanups
--------
Some of unused utils were removed. There is still some code in utils part that is not used by the library,
but I need this tollbox in many other places and don't want to maintain two versions.
Some unification in integer types; ``size_t`` seems to be the best choice for and integer representing machine
word (``unsigned long`` is not long enough on windows), less utils dependencies, less compiler warnings.
|