path_storage的设计思想

Now it's all about path_storage and the internal containers. I've got fair 
criticism that it was too expensive to create many path_storage objects. 
Each of them allocated memory for at least 256 vertices. That's true and in 
certain cases it caused huge memory overhead.

Now I separated the path_storage functionality from used containers so that, 
you can use std::vector or std::deque if you wish. Now path_storage is 
declared as:

typedef path_base<vertex_block_storage<double> > path_storage;

And it has exactly the same functionality and behaviour as the former 
path_storage. But now it's  much more flexible.

path_base is just a wrapper over some vertex container that provides 
traditional path interface (move_to/line_to/etc) and the VertexSource 
interface.

vertex_block_storage is what was embedded in the path_storage. Now it's a 
template:

    template<class T, unsigned BlockShift=8, unsigned BlockPool=256>
    class vertex_block_storage
    . . .

It means you can use floats or even integers for coordinates. Besides, you 
can change the block size. For example:
It means you can use floats or even integers for coordinates. Besides, you 
can change the block size. For example:

typedef path_base<vertex_block_storage<float, 4, 16> > path_storage;
will allocate memory for 16 vertices in floats and 16 pointers.

But it's not only that. You can use any available container:

    struct vertex
    {
        typedef float value_type;
        float x,y;
        unsigned cmd;
        vertex() {}
        vertex(float x_, float y_, unsigned cmd_) : x(x_), y(y_), cmd(cmd_) 
{}
    };


typedef path_base<vertex_stl_storage<std::vector<vertex> > > path_storage;

Here std::vector<vertex> will be used. vertex_stl_storage is an adaptor that 
provides the necessary functionality for path_base.

The container must be compatible with random access STL one (std::list won't 
work) and have the following traits:
typedef "vertex_type" value_type;
void clear();
void push_back(vertex_type);
vertex_type& operator [] (unsigned idx);

I have modified the internal AGG containers so that they are compatible with 
STL too. You can use:

typedef path_base<vertex_stl_storage<pod_bvector<vertex> > > path_storage;


The main difference between vertex_block_storage and vertex_stl_storage is 
in memory allocation strategy. vertex_block_storage is compact, but has 
constant memory overhead of at most 1<<BlockShift vertices. Also, it never 
reallocates memory, it only allocates new blocks of a constant size. But 
it's not a good idea to create thousands of path_storage objects, because 
that very "constant memory overhead" becomes significant.

On the other hand you can use

    struct vertex
    {
        double x,y;
        unsigned char cmd;
    };
and std::vector<vertex>. But there is another problem. Struct vertex is 
aligned to the size of double and in general there's no way to avoid it. It 
means that instead of 17 bytes (8+8+1) it will have sizeof(vertex)=24. If 
you have one million vertices stored in one path, the difference becomes 
significant: 17 megs or 24 megs - it's about 40%. In this case it's much 
better to use vertex_block_storage and increase the block size:

vertex_block_storage<double, 12>

Here we will have blocks of 1<<12=4096 vertices.

The bottom line is. If you want to create one path_storage with huge number 
of vertices it's better to use vertex_block_storage.
If you want to create many objects with just few vertices it's better to use 
vertex_stl_storage adaptor.
But there's no universal solution, it all depends on the container. Well, 
you can also write your own container.

Also, there's a way to use a very lightweight container that will not 
allocate any memory in heap:

        // Here we declare a very cheap-in-use path storage.
        // It allocates space for at most 20 vertices in stack and
        // never allocates memory. But be aware that adding more than
        // 20 vertices is fatal!
        //------------------------
        typedef agg::path_base<
            agg::vertex_stl_storage<
                agg::pod_auto_vector<
                    agg::vertex_d, 20> > > path_storage_type;
        path_storage_type path;

pod_auto_vector allocates memory in stack and if you are absolutely sure you 
never add more than 20 vertices you can use it. It can be important in some 
wrappers for basic shapes that expose the VertexSource interface.

It's all may be important in embedded programming, for example.
=========================
Another change is with add_path. It was very confusing. Now there're are two 
functions:

concat_path(path, path_id);
join_path(path, path_id);

The first one just adds the path "as is" and it's equivalent to former 
add_path(path, 0, false); The second one joins the vertices, that is, 
continues the path ignoring "move_to" commands. It works as if you had a 
protter with broken pen mechanism and the pen was always down. Besides, 
join_path removes the first vertex if it coincides with the last one in the 
existing path. It's important in "arc_to" Stephan noticed.

Both functions are important and thre was some confusion.

Also, I have added some utility classes:
poly_plain_adaptor
line_adaptor

It's not that considerable, but might be useful in some cases. For example,
methods concat_poly and join_poly use this poly_plain_adaptor internally.

=============================
Renames:
I have renamed container classes.

pod_deque -> pod_bvector

Deque is a neologism that refers to "Double End QUEue". agg::pod_deque was a 
container that was organized in a similar way as std::deque, but it hadn't 
method push_front. So, it's just a block container that never reallocates 
memory. There's no analog in STL.

Other renames:
pod_array -> pod_vector
pod_heap_array -> pod_array

And added pod_auto_vector.
The difference between "vector" and "array" is that vector requires to call 
add(element) to increase the size (std::vector-like behaviour). "array" has 
always constant size and it basically is a simple wrapper over memory 
allocation.
Note: I don't want to discuss "reinventing the wheel" issues. Mostly because 
STL doesn't have adequate containers. BOOST has them, but it's not a 
standard. BOOST is the last resort for AGG. As soon as AGG depends on BOOST 
you can bury it. :-)


==============================

Qestions:
1. I don't like name path_base. Could you suggest some other one?
2. path_storage is defined as it was before (same behaviour and 
functionality). I feel there can be several different pre-defined 
(typedefed) storages. Please suggest some. It also makes sense to rename 
path_storage. What would be the best name for a "path storage that allocates 
memory in blocks of 256 vertices and keeps data compact"?
3. Do you feel comfortable with concat_path/join_path?
4. Any other suggestions about all that stuff?


你可能感兴趣的:(agg,path_storage)