
Ok, this is awesome. Last week I made changes in the Sandbox I had to revert and rework all over... Now the changes I made in both the pointer and the STL containers are clearly to ones I want to stick with. This brings up interesting concepts at the same time, such as: what should be the right parameter of allocator::deallocate() ? We can't use a raw pointer over there. We can see the non-official patch inside the bits folder and shifted_allocator.hpp which I think solves the problem correctly. Furthermore allocator::allocate() I beleive shouldn't return yet a smart pointer because it creates unnecessary temporaries which can be costly, depending on the smart pointer used. So the typedefs inside shifted_allocator are the way I think they should be understood by the containers... Thanks, -Phil

You guys are following me? I think we are surrounded by aphonia and I can't tell what needs to be known. Right now shifted_ptr_test2.cpp works perfectly fine with the slightly adapted STL container to smart pointers and using special allocators needed to define all internal characteristics used by the container. We see in shifted_allocator: template <typename T> class shifted_allocator { public: typedef shifted<T> value_type; typedef shifted_ptr<T> pointer; typedef const shifted_ptr<T> const_pointer; ... }; - value_type: being the real concrete type expected by the smart pointer - pointer: defines the node pointer used internaly by the container Hence this leaves us with opened door yet to be defined. The following member functions, parameters and return type are correct but their implementation are questionnable. Right now this implemenation is brute force and expect type T having a default constructor but this is not exactly what we want. The commented version would be what we are looking for but creates ugly temporaries, therefore some different approach needs to be taken: template <typename T> class shifted_allocator { ... value_type * allocate(size_type s, const void * = 0) { //value_type * p = (value_type *) value_type::operator new(sizeof(value_type)); value_type * p = new value_type(); return p; } void deallocate(pointer & p, size_type) { } void construct(value_type * p, const T & x) { //::new (p) owned_base; //::new (p->element()) T(x); } void destroy(pointer & p) { p.reset(); } }; Thanks, -Phil "Phil Bouchard" <philippe@fornux.com> wrote in message news:g779rk$78a$1@ger.gmane.org...
Ok, this is awesome. Last week I made changes in the Sandbox I had to revert and rework all over... Now the changes I made in both the pointer and the STL containers are clearly to ones I want to stick with. This brings up interesting concepts at the same time, such as: what should be the right parameter of allocator::deallocate() ? We can't use a raw pointer over there. We can see the non-official patch inside the bits folder and shifted_allocator.hpp which I think solves the problem correctly. Furthermore allocator::allocate() I beleive shouldn't return yet a smart pointer because it creates unnecessary temporaries which can be costly, depending on the smart pointer used. So the typedefs inside shifted_allocator are the way I think they should be understood by the containers...
Thanks, -Phil
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Aug 5, 2008, at 2:22 AM, Phil Bouchard wrote: [SNIP]
Right now shifted_ptr_test2.cpp works perfectly fine with the slightly adapted STL container to smart pointers and using special allocators needed to define all internal characteristics used by the container. We see in shifted_allocator:
template <typename T> class shifted_allocator { public: typedef shifted<T> value_type; typedef shifted_ptr<T> pointer; typedef const shifted_ptr<T> const_pointer; ... };
- value_type: being the real concrete type expected by the smart pointer - pointer: defines the node pointer used internaly by the container [TRUNCATE]
Isn't "const_pointer" supposed to be an analogue of "T const *"? Right now, you have it represent "T * const", which definitely isn't the same thing! -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message news:BAY115-DAV9D530B17A66EBC82F5C17BF770@phx.gbl... [...]
template <typename T> class shifted_allocator { public: typedef shifted<T> value_type; typedef shifted_ptr<T> pointer; typedef const shifted_ptr<T> const_pointer; ... };
- value_type: being the real concrete type expected by the smart pointer - pointer: defines the node pointer used internaly by the container [TRUNCATE]
Isn't "const_pointer" supposed to be an analogue of "T const *"? Right now, you have it represent "T * const", which definitely isn't the same thing!
Yes, sorry about that and thanks for the notice. It should be: typedef shifted_ptr<const T> const_pointer; -Phil

Just for the records... Smart pointers inside containers is a wide term. I mean here all sorts of pointer wrappers that can track various statistics for example or use totally different allocators requiring special pointer wrapper like Bob Walters wants to approach. In my case I am mostly interested into pure smart pointers and hopefully shared_ptr can easily be used using the modifications I am proposing. We could for example partly mix congruent lists without worrying about the irreversable mess it could create. But a map controled partly by another map sharing nodes is something I am mostly interested in because you can access the same nodes but using "shortcuts" or different roots... -Phil

In my case I am mostly interested into pure smart pointers and hopefully shared_ptr can easily be used using the modifications I am proposing. We could for example partly mix congruent lists without worrying about the irreversable mess it could create. But a map controled partly by another map sharing nodes is something I am mostly interested in because you can access the same nodes but using "shortcuts" or different roots...
That's neat and I would like to see an implementation - I think you would end up with something like the Furnas/Zacks "multitrees" - quoting from their paper, the multitree "has the unusual property that although it is not a tree, the descendents of any node form a tree... Multi-trees are DAGs, not trees, and as a result a node in the structure can have multiple parents... Not only does the set of descendents of any node form a tree, the set of its ancestors also form an inverted tree." But to get there wouldn't you need to change the public interface of set/map? Right now it won't even admit it's holding a tree. Wouldn't you have to teach it how to reuse nodes rather than creating new ones? I also think there might be overlap issues between an inserted tree and its new siblings. For list, you *might* be able to keep the same interface, but the invariants would be much stranger if one list could modify another. In sum, I'm very interested in these data structures, I just wonder if they might be better served by new classes rather than modifications to STL. Your original application in garbage collection seems valid to me, although I am no allocator expert. Cheers, Gordon

"Gordon Woodhull" <gordon@woodhull.com> wrote in message news:56F3BD3B-DAC3-43B1-96F5-4BB4A3919B10@woodhull.com... [...]
But to get there wouldn't you need to change the public interface of set/map? Right now it won't even admit it's holding a tree. Wouldn't you have to teach it how to reuse nodes rather than creating new ones? I also think there might be overlap issues between an inserted tree and its new siblings. For list, you *might* be able to keep the same interface, but the invariants would be much stranger if one list could modify another.
Well if we could have external access to the nodes themselves we could do a lot. I think this should be a task delegated to iterators. I do not wish to elaborate to much at this time because it is late and I would like demonstrating another useful example. The following doesn't work yet and I found another bug I need to correct but the idea is relatively easy to get. Here's an example on how we could write a "human brain kernel", which is all it basically really is: https://svn.boost.org/svn/boost/sandbox/shifted_ptr/libs/smart_ptr/example/r...
In sum, I'm very interested in these data structures, I just wonder if they might be better served by new classes rather than modifications to STL. Your original application in garbage collection seems valid to me, although I am no allocator expert.
Everybody has their own preferences but personnaly I do not have strong beliefs in new classes. Functional programming is a very powerful option and nesting up these containers would be very extendible I think. But this should be up to the programmer to see his options. Thanks, -Phil

On Aug 6, 2008, at 5:50 AM, Phil Bouchard wrote:
Well if we could have external access to the nodes themselves we could do a lot.
Absolutely, I think that would be wonderful.
I think this should be a task delegated to iterators.
Do you mean, there would be special iterator types that mean "reuse these nodes" instead of "copy these"? Or do you have some other way of preserving the public interface of e.g. std::set while adding the shared node functionality? I think we are working on complementary problems having to do with better ways to manage systems of objects that point to each other. In the metagraph library, I am working with fusion and intrusive to build up objects that are e.g. nodes in graphs and also items in lists and also nodes in trees, all at the same time. Really the "is also" is what intrusive allows and I'm trying to describe these systems better using metagraph patterns, which are metadata graphs describing object types ("roles") and the other types they point to or contain ("relations"). I haven't really considered ownership or GC (don't need it for my app, Dynagraph), so I imagine your techniques (or hopefully, library) could be useful for people with metagraphs who want automatic lifetime management.
The following doesn't work yet and I found another bug I need to correct but the idea is relatively easy to get. Here's an example on how we could write a "human brain kernel", which is all it basically really is: https://svn.boost.org/svn/boost/sandbox/shifted_ptr/libs/smart_ptr/example/r...
If I understand correctly, it's a kind of neural net and shifted_ptr would delete regions when they become detached?
In sum, I'm very interested in these data structures, I just wonder if they might be better served by new classes rather than modifications to STL. Your original application in garbage collection seems valid to me, although I am no allocator expert.
Everybody has their own preferences but personnaly I do not have strong beliefs in new classes.
Agnostic here - whatever works best. I was assuming that you would have to make massive changes to the public interfaces of the STL containers; now I am not so sure that is true.
Functional programming is a very powerful option and nesting up these containers would be very extendible I think. But this should be up to the programmer to see his options.
I think I agree. What I am trying to understand is that your library seems to be about lifetime management, but then you are also talking about adding all this cool new functionality to the standard containers. Do you anticipate adding new methods to STL containers, or is the "external access to the nodes" via shifted_ptr itself? How would you express the command, "splice this subtree into another container"? If your library reflects a system of objects at runtime so that any pointers between them are traversable, then I think there might some interesting synergy with what I'm working on, which is about describing pointers between types at compile time. Thanks, Gordon

"Gordon Woodhull" <gordon@woodhull.com> wrote in message news:EC4056C7-4D91-4591-A2CC-D909A6340FF6@woodhull.com... [...]
Do you mean, there would be special iterator types that mean "reuse these nodes" instead of "copy these"? Or do you have some other way of preserving the public interface of e.g. std::set while adding the shared node functionality?
I think having classes derived from nodes would be a great idea. I have improved the example I submitted yesterday with a new one. I haven't fixed the run time bug yet but once again the code is fairly easy to understand. I added some code making our brain learning and I am using a global map pointing to the neurons themselves. This is a great example in this scenario adn we can see how we could benefit from these nodes. Imagine the map uses our class called "map_node" as a template parameter for example. We could explicitly attach neurons with nodes and not suffering from all these temporary little nodes having pointer to neuron as data members we currently have. This way the map will refer to the same object allocated on the heap. Let's take a look at the following file: https://svn.boost.org/svn/boost/sandbox/shifted_ptr/libs/smart_ptr/example/t... [...]
I haven't really considered ownership or GC (don't need it for my app, Dynagraph), so I imagine your techniques (or hopefully, library) could be useful for people with metagraphs who want automatic lifetime management.
Just for the record... I am not using garbage collection at all. Nothing is being collected and no periodic system slowdown is required. [...]
If I understand correctly, it's a kind of neural net and shifted_ptr would delete regions when they become detached?
Precisely, just disregard that deallocation problem and expect objects being destructed in real time. [...]
Agnostic here - whatever works best. I was assuming that you would have to make massive changes to the public interfaces of the STL containers; now I am not so sure that is true.
No, we can see some of them in the following sample patch file: https://svn.boost.org/svn/boost/sandbox/shifted_ptr/bits/stl_list.h.patch [...]
What I am trying to understand is that your library seems to be about lifetime management, but then you are also talking about adding all this cool new functionality to the standard containers. Do you anticipate adding new methods to STL containers, or is the "external access to the nodes" via shifted_ptr itself? How would you express the command, "splice this subtree into another container"?
The first file I was previously refering to is an example of what I think would fit best; i.e. by defining our own nodes and using them as a container template parameter. "splice this subtree into another container" is exactly what I am looking for and I am very interested into searching only part of a tree, not the entire tree. Maybe by creating a new map constructor defining the beginning and the end of the new map using iterators, but in contrast to the actual one we don't want to duplicate the nodes. It should therefore be reasonnably fast.
If your library reflects a system of objects at runtime so that any pointers between them are traversable, then I think there might some interesting synergy with what I'm working on, which is about describing pointers between types at compile time.
I am not sure what you are referring to but hopefully you have a better overview of what it actually is and where it is going. STL support for smart pointers is imminent. Bests, -Phil

"Phil Bouchard" <philippe@fornux.com> wrote in message news:g7elor$eue$1@ger.gmane.org... [...]
Let's take a look at the following file: https://svn.boost.org/svn/boost/sandbox/shifted_ptr/libs/smart_ptr/example/t...
I just added better comments on what needs to be done. -Phil

"Gordon Woodhull" <gordon@woodhull.com> wrote in message news:EC4056C7-4D91-4591-A2CC-D909A6340FF6@woodhull.com... [...]
I think we are working on complementary problems having to do with better ways to manage systems of objects that point to each other. In the metagraph library, I am working with fusion and intrusive to build up objects that are e.g. nodes in graphs and also items in lists and also nodes in trees, all at the same time. Really the "is also" is what intrusive allows and I'm trying to describe these systems better using metagraph patterns, which are metadata graphs describing object types ("roles") and the other types they point to or contain ("relations").
Intrusive node pointers cannot be owners of the object referred to. If we include all the necessary node pointers according to the number of containers pointing to the node itself then we could take advantage of all the container properties combined at the same time: struct node : list_node, map_node, vector_node { char c_; node(char c = '') : c_(c) {} bool operator < ()... bool operator == ()... }; node elements[] = (node *) {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't'}; // e prefix here stands for "explicit": elist<node> l(element, element + sizeof(elements) / sizeof(* elements)); emap<node> m(element, element + sizeof(elements) / sizeof(* elements)); evector<node> v(element, element + sizeof(elements) / sizeof(* elements)); cout << v[6].c_ << endl; cout << m.find("a")->c_ << endl; Here the vector will have to support index fragmentation if we start inserting objects between consecutive ones: (l.begin() ++ ++)->insert('h'); [...]
What I am trying to understand is that your library seems to be about lifetime management, but then you are also talking about adding all this cool new functionality to the standard containers. Do you anticipate adding new methods to STL containers, or is the "external access to the nodes" via shifted_ptr itself? How would you express the command, "splice this subtree into another container"?
I am already adapting the current Gcc Libstdc++ containers to support smart pointers. All the details related to explicit node access haven't been discussed yet but any contributions to this are welcome. [...] Bests, -Phil

On Aug 8, 2008, at 3:43 AM, Phil Bouchard wrote:
"Gordon Woodhull" <gordon@woodhull.com> wrote in message news:EC4056C7-4D91-4591-A2CC-D909A6340FF6@woodhull.com...
I think we are working on complementary problems having to do with better ways to manage systems of objects that point to each other. In the metagraph library, I am working with fusion and intrusive to build up objects that are e.g. nodes in graphs and also items in lists and also nodes in trees, all at the same time. Really the "is also" is what intrusive allows and I'm trying to describe these systems better using metagraph patterns, which are metadata graphs describing object types ("roles") and the other types they point to or contain ("relations").
Intrusive node pointers cannot be owners of the object referred to.
True, Boost.Intrusive doesn't address ownership (except for the simplest case). Usually a container doesn't own objects, and erase just wipes the internal pointers. It is assumed that something else controls lifetime. I think that the principles of ownership and the lifetime management system you are proposing could probably be applied to systems of intrusive containers, more quickly than a change to the c++ standard (perhaps via the metagraph library I'm working on ;).
If we include all the necessary node pointers according to the number of containers pointing to the node itself then we could take advantage of all the container properties combined at the same time:
struct node : list_node, map_node, vector_node [...]
This looks to me like a refactoring of what Boost.Intrusive does, except for the ownership/lifetime management functionality, and of course there is no such thing as an intrusive vector! To achieve the same effect (I think) as your code with Boost.Intrusive, one would put the properly annotated (in a similar way) objects into a std::vector and then insert them (which just updates internal pointers) into the intrusive "containers". Of course, now the vector owns them, which might not be what is wanted. Still, I think that any ownership pattern could be imposed on Intrusive somehow. Your design may be more elegant, we'll see... :-)
Here the vector will have to support index fragmentation if we start inserting objects between consecutive ones: (l.begin() ++ ++)->insert('h');
By "index fragmentation," do you mean std::vector should remap indices to accommodate any changes? That sounds really neat, but does that logic really belong there and not in some other class with different performance guarantees?
I am already adapting the current Gcc Libstdc++ containers to support smart pointers. All the details related to explicit node access haven't been discussed yet but any contributions to this are welcome.
I'm pretty dedicated to solutions that don't involve changing the standard, so I'll look into how your ownership model fits in with intrusive containers. But at the same time I am really eager to see your redesign - it is such a dramatically different approach, and STL could surely be generalized better. It sounds like you are solving some of the same multi-index problems as Boost.Intrusive, but also some other interesting problems: 1. opening up the internal structure of sets and lists and allowing it to be shared. 2. super-efficient lifetime management. Honestly, I don't see how the structure really can be shared and preserve the invariants of both containers, but I would love to be proved wrong and it would surely be amazing and useful if it worked. This objection has nothing to do with shifted_ptr "extrusions" vs intrusive methods, just with the problems of two objects mucking about with the same data. But just about everything else I heard "can't be done in C++" over the years, has been done. Looking forward to learning more, Gordon IMO it's time for more things that can *only* be done in C++.

"Gordon Woodhull" <gordon@woodhull.com> wrote in message news:A671761D-B76D-4C0C-86A6-592023FCFABC@woodhull.com... [...]
I think that the principles of ownership and the lifetime management system you are proposing could probably be applied to systems of intrusive containers, more quickly than a change to the c++ standard (perhaps via the metagraph library I'm working on ;).
Intrusive containers are very useful and shifted_ptr itself uses its own version of intrusive_list and intrusive_stack (which isn't present in Boost.Intrusive BTW). But even if ownership support isn't impossible adding for intrusive containers, the latter was not made for this (can refer to objects on the stack) and so are generic smart pointers not made for differenciating objects living on the stack or data segments with heap blocks. [...]
Here the vector will have to support index fragmentation if we start inserting objects between consecutive ones: (l.begin() ++ ++)->insert('h');
By "index fragmentation," do you mean std::vector should remap indices to accommodate any changes? That sounds really neat, but does that logic really belong there and not in some other class with different performance guarantees?
It cannot belong to std::vector only, but to the main supercontainer class linking all of them and supporting it if necessary. But I haven't implemented anything as such yet but the index fragmentation I'm talking about consists of mapping indices to range of iterators so that an insertion in the middle of a vector by the list handler is transparent to the vector and random access to the nodes still is a constant time operation in the average case scenario. For example I got: node elements[] = (node *) {'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't'}; elist<node> l(element, element + sizeof(elements) / sizeof(* elements)); evector<node> v(element, element + sizeof(elements) / sizeof(* elements)); // Insert operation using the elist (-- l.end())->insert('.'); // The evector::operator [] (size_t p) would map ranges as such: if 15 -> return node '.' if 0 - 16 -> return node 'T' to 't' I think a huge container inside an application will always suffer from imperfections and this could be a decent alternative to the problem. A map mixed with a list, a vector mixed with a set or all four together offers an infinite set of properties. [...]
But at the same time I am really eager to see your redesign - it is such a dramatically different approach, and STL could surely be generalized better.
Well we now have exclusive problems we want to fix. We have: - Smart pointer support for STL (pointer wrappers are useful for some allocators) - Supercontainer with shared access to nodes The latter here would be reused code from the STL all mixed together. There is no C++ standard redesign here, simply a Gnu Libstdc++ code extension. [...] Thanks, -Phil

"Gordon Woodhull" <gordon@woodhull.com> wrote in message news:A671761D-B76D-4C0C-86A6-592023FCFABC@woodhull.com... [...]
I think that the principles of ownership and the lifetime management system you are proposing could probably be applied to systems of intrusive containers, more quickly than a change to the c++ standard (perhaps via the metagraph library I'm working on ;).
[...] Let's put it this way. All new "unordered" and multiset containers could easily be implemented as: 1) superc1st<double, list, vector> s1; 2) superc2nd<string, double, map, vector> s2; 3) superc2nd<string, double, map, map> s3; Where (explicit specializations for sake of example and please disregard missing "typename"s): 1) template <> class superc1st<double, list, vector> : public _list<0, void, double>, _vector<1, void, double> {...}; Here are examples of its usage: s1.push_back(5.7); s2[0] = 5.8; 2) template <> class superc2nd<string, double, map, vector> : public _map<0, string, double>::base, _vector<1, string, double>::base {...}; This one can be accessed as such: s2["Height"] = 6.3; // <-- O(log n) s2[10] = 5.9; // <-- O(1) 3) template <> class superc2nd<string, double, map, map> : public _map<0, string, double>::base, _map<1, string, double>::base {...}; To access 3) we could add indexed types we can cast the container to: s3.get<0>()["Age"] = 31; The underscored containers will be defined as: template <int I, typename T, typename U> struct _map : std::map<T, U> { typedef std::map<T, U> base; base & get<I>() { return * this; } // we can't specialize functions but you get the idea }; And: template <int I, typename T, typename U> struct _vector : std::vector<U> { typedef std::vector<U> base; ... }; ... I think this is very easy to implement, cleaner and much more flexible (can use vectors and no container can be forgotten). My brain kernel example already needs something similar extensively... Thanks, -Phil

Here is a discussion I started with Gordon 2 weeks ago and I wanted to share globally because of its interesting features which aren't related to smart pointers: "I think a huge container inside an application will always suffer from imperfections and this could be a decent alternative to the problem. A map mixed with a list, a vector mixed with a set or all four together offers an infinite set of properties. Let's put it this way. All new "unordered" and multiset containers could easily be implemented as: 1) superc1st<double, list, vector> s1; 2) superc2nd<string, double, map, vector> s2; 3) superc2nd<string, double, map, map> s3; Where (explicit specializations for sake of example and please disregard missing "typename"s): 1) template <> class superc1st<double, list, vector> : public _list<0, void, double>, _vector<1, void, double> {...}; Here are examples of its usage: s1.push_back(5.7); s1[0] = 5.8; 2) template <> class superc2nd<string, double, map, vector> : public _map<0, string, double>::base, _vector<1, string, double>::base {...}; This one can be accessed as such: s2["Height"] = 6.3; // <-- O(log n) s2[10] = 5.9; // <-- O(1) 3) template <> class superc2nd<string, double, map, map> : public _map<0, string, double>::base, _map<1, string, double>::base {...}; To access 3) we could add indexed types we can cast the container to:s3.get<0>()["Age"] = 31; The underscored containers will be defined as: template <int I, typename T, typename U> struct _map : std::map<T, U> { typedef std::map<T, U> base; base & get<I>() { return * this; } // explicit function spec. won't work here (should be Ith type pack cast) }; And: template <int I, typename T, typename U> struct _vector : std::vector<U> { typedef std::vector<U> base; ... }; ... I think this is very easy to implement, cleaner and much more flexible (can use vectors and no container can be forgotten). My brain kernel example already needs something similar extensively..." Thanks, -Phil

on Sun Aug 17 2008, "Phil Bouchard" <philippe-AT-fornux.com> wrote:
"I think a huge container inside an application will always suffer from imperfections and this could be a decent alternative to the problem. A map mixed with a list, a vector mixed with a set or all four together offers an infinite set of properties.
Let's put it this way. All new "unordered" and multiset containers could easily be implemented as: 1) superc1st<double, list, vector> s1; 2) superc2nd<string, double, map, vector> s2; 3) superc2nd<string, double, map, map> s3;
Sounds reminiscent of boost::graph::adjacency_list. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
participants (4)
-
Daryle Walker
-
David Abrahams
-
Gordon Woodhull
-
Phil Bouchard