digitalmars.D - sorting hidden data.
- Steven Schveighoffer (30/30) Sep 29 2010 I'm adding a new class to dcollections -- Deque of STL fame.
- Andrei Alexandrescu (6/20) Sep 29 2010 Good news - you should be able to use sort on sealed ranges if they
- dsimcha (16/38) Sep 29 2010 Actually, this gives me the opportunity to bring up a point I've been me...
- Andrei Alexandrescu (4/42) Sep 29 2010 Yah. I've been with a foot in the air regarding this until Walter
- Jacob Carlborg (5/64) Sep 29 2010 Would that be the uniform function call syntax that I've been waiting
- Andrei Alexandrescu (17/19) Sep 29 2010 Yah. One unpleasant issue I found with it (as it's already implemented
- Steven Schveighoffer (4/22) Oct 04 2010 __traits(hasMember, r, "moveFront") && rest_of_expression_you_had
- Andrei Alexandrescu (8/34) Oct 04 2010 Yah, I know - in fact I added a trait hasMember(T, "name") to std.traits...
- Steven Schveighoffer (12/33) Sep 29 2010 I'm not liking this...
- Pelle (3/38) Sep 29 2010 I'm agreeing with this. Maybe because I don't really understand what
- Andrei Alexandrescu (3/38) Sep 29 2010 It could, if we decided to punt on types with expensive constructors.
- Steven Schveighoffer (10/55) Sep 29 2010 What I mean is, why is it automatically assumed that if front does not
- Andrei Alexandrescu (6/10) Sep 29 2010 Good point. We should arrange things such that all types without
- Steven Schveighoffer (12/20) Sep 29 2010 Well, this isn't exactly what I said, but it makes sense. If there is a...
- Jonathan M Davis (10/32) Sep 29 2010 The real problem then is in any structs with elaborate copy constructors...
- dsimcha (21/31) Sep 29 2010 This should already work (I noticed that it didn't a long time ago and c...
- dsimcha (7/42) Sep 29 2010 I somewhat agree, but apparently noone noticed my other post. moveFront...
- Steven Schveighoffer (24/34) Sep 29 2010 I did see your other post. From reading the docs for moveFront and
- BLS (9/10) Sep 29 2010 Hi Steve,
- Steven Schveighoffer (6/15) Sep 29 2010 hehe, I haven't had any real interesting D projects to do for a while :)...
I'm adding a new class to dcollections -- Deque of STL fame. A deque implements dcollections' List interface, and one of the requirements of the List interface is to be able to sort elements. One important property of most dcollections containers is that data is not exposed. This means you cannot get an address to the internal storage of elements. The one exception is ArrayList (which purposely exposes its representation via an array). I initially wanted to make Deque also hide its internals, but I ran into a significant snag. std.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} } You cannot use std.algorithm.sort on this range. So my current workaround is to allow ref return on front(). My questions are: 1. Does it make sense to allow ref access to Deque? 2. Is there a way to use std.algorithm.sort on myrange above? 3. Might people have interest in a "property delegate" that allows one to pass the ability to set/get a property? e.g.: auto pdelegate = getPropertyDelegate!"front"(r); -Steve
Sep 29 2010
On 9/29/10 6:22 PDT, Steven Schveighoffer wrote:std.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition. Andrei
Sep 29 2010
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleOn 9/29/10 6:22 PDT, Steven Schveighoffer wrote:Actually, this gives me the opportunity to bring up a point I've been meaning to bring up. moveFront() and friends don't even need to be explicitly defined. The module level function moveFront() in std.range defines default behavior in the following cases: 1. If the range's elements don't have elaborate copy construction, moveFront just forwards to front. 2. If the range's elements are lvalues, std.algorithm.move(range.front) can give the proper behavior. Of course, these are just defaults and can be overridden by explicitly defining moveFront() even where they apply. If range.moveFront() is explicitly defined, the module level function always forwards to it no matter what. The situation has gradually evolved into this state due to discussions on Bugzilla and the Phobos list and the impracticality of forcing explicit moveFront() on all ranges. Unless it's still subject to change, it should probably be documented somewhere.std.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition. Andrei
Sep 29 2010
On 9/29/10 9:52 PDT, dsimcha wrote:== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleYah. I've been with a foot in the air regarding this until Walter figures out what to do about the rule a.f(b) -> f(a, b). AndreiOn 9/29/10 6:22 PDT, Steven Schveighoffer wrote:Actually, this gives me the opportunity to bring up a point I've been meaning to bring up. moveFront() and friends don't even need to be explicitly defined. The module level function moveFront() in std.range defines default behavior in the following cases: 1. If the range's elements don't have elaborate copy construction, moveFront just forwards to front. 2. If the range's elements are lvalues, std.algorithm.move(range.front) can give the proper behavior. Of course, these are just defaults and can be overridden by explicitly defining moveFront() even where they apply. If range.moveFront() is explicitly defined, the module level function always forwards to it no matter what. The situation has gradually evolved into this state due to discussions on Bugzilla and the Phobos list and the impracticality of forcing explicit moveFront() on all ranges. Unless it's still subject to change, it should probably be documented somewhere.std.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition. Andrei
Sep 29 2010
On 2010-09-29 19:42, Andrei Alexandrescu wrote:On 9/29/10 9:52 PDT, dsimcha wrote:Would that be the uniform function call syntax that I've been waiting for since I first heard of it? -- /Jacob Carlborg== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleYah. I've been with a foot in the air regarding this until Walter figures out what to do about the rule a.f(b) -> f(a, b). AndreiOn 9/29/10 6:22 PDT, Steven Schveighoffer wrote:Actually, this gives me the opportunity to bring up a point I've been meaning to bring up. moveFront() and friends don't even need to be explicitly defined. The module level function moveFront() in std.range defines default behavior in the following cases: 1. If the range's elements don't have elaborate copy construction, moveFront just forwards to front. 2. If the range's elements are lvalues, std.algorithm.move(range.front) can give the proper behavior. Of course, these are just defaults and can be overridden by explicitly defining moveFront() even where they apply. If range.moveFront() is explicitly defined, the module level function always forwards to it no matter what. The situation has gradually evolved into this state due to discussions on Bugzilla and the Phobos list and the impracticality of forcing explicit moveFront() on all ranges. Unless it's still subject to change, it should probably be documented somewhere.std.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition. Andrei
Sep 29 2010
On 9/29/10 13:10 PDT, Jacob Carlborg wrote:Would that be the uniform function call syntax that I've been waiting for since I first heard of it?Yah. One unpleasant issue I found with it (as it's already implemented for arrays) is a chicken-and-egg thing: say I want to provide operation moveFront only if the type doesn't define it yet. Without UCF (Uniform Call Syntax) things are simple: auto moveFront(R)(ref R r) if (!is(typeof(r.moveFront())) && !hasElaborateCopy!(ElementType!R)) { return r.front; } With UCF things get messy because introducing moveFront at global level does make r.moveFront() legit, so the if clause returns true, which is weird because the function shouldn't have been introduced yet. So the compiler gets confused by this lying Cretan riddle - it recurses forever (when R is an array). The solution would be probably to not consider the symbol introduced until the if-clause has cleared. Andrei
Sep 29 2010
On Wed, 29 Sep 2010 16:37:34 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 9/29/10 13:10 PDT, Jacob Carlborg wrote:__traits(hasMember, r, "moveFront") && rest_of_expression_you_had -SteveWould that be the uniform function call syntax that I've been waiting for since I first heard of it?Yah. One unpleasant issue I found with it (as it's already implemented for arrays) is a chicken-and-egg thing: say I want to provide operation moveFront only if the type doesn't define it yet. Without UCF (Uniform Call Syntax) things are simple: auto moveFront(R)(ref R r) if (!is(typeof(r.moveFront())) && !hasElaborateCopy!(ElementType!R)) { return r.front; } With UCF things get messy because introducing moveFront at global level does make r.moveFront() legit, so the if clause returns true, which is weird because the function shouldn't have been introduced yet. So the compiler gets confused by this lying Cretan riddle - it recurses forever (when R is an array). The solution would be probably to not consider the symbol introduced until the if-clause has cleared.
Oct 04 2010
On 10/4/10 6:29 CDT, Steven Schveighoffer wrote:On Wed, 29 Sep 2010 16:37:34 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Yah, I know - in fact I added a trait hasMember(T, "name") to std.traits that hides the __traits. For some reason that still has issues, probably due to lack of short-circuit evaluation of && during compilation (but I'm not positive). Things are still unpleasant even assuming that works, so I think we need to look into that when considering committing to uniform call syntax. AndreiOn 9/29/10 13:10 PDT, Jacob Carlborg wrote:__traits(hasMember, r, "moveFront") && rest_of_expression_you_had -SteveWould that be the uniform function call syntax that I've been waiting for since I first heard of it?Yah. One unpleasant issue I found with it (as it's already implemented for arrays) is a chicken-and-egg thing: say I want to provide operation moveFront only if the type doesn't define it yet. Without UCF (Uniform Call Syntax) things are simple: auto moveFront(R)(ref R r) if (!is(typeof(r.moveFront())) && !hasElaborateCopy!(ElementType!R)) { return r.front; } With UCF things get messy because introducing moveFront at global level does make r.moveFront() legit, so the if clause returns true, which is weird because the function shouldn't have been introduced yet. So the compiler gets confused by this lying Cretan riddle - it recurses forever (when R is an array). The solution would be probably to not consider the symbol introduced until the if-clause has cleared.
Oct 04 2010
On Wed, 29 Sep 2010 12:26:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 9/29/10 6:22 PDT, Steven Schveighoffer wrote:I'm not liking this... How many more boiler-plate functions will we be forced to add in order to support standard ranges? save() was bad enough, this is three more, when the functionality *already exists*. Can't sort just use: x = r1.front; r1.front = r2.front; r2.front = x; ??? -Stevestd.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition.
Sep 29 2010
On 09/29/2010 07:10 PM, Steven Schveighoffer wrote:On Wed, 29 Sep 2010 12:26:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I'm agreeing with this. Maybe because I don't really understand what move() and friends are good for.On 9/29/10 6:22 PDT, Steven Schveighoffer wrote:I'm not liking this... How many more boiler-plate functions will we be forced to add in order to support standard ranges? save() was bad enough, this is three more, when the functionality *already exists*. Can't sort just use: x = r1.front; r1.front = r2.front; r2.front = x; ??? -Stevestd.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition.
Sep 29 2010
On 9/29/10 10:10 PDT, Steven Schveighoffer wrote:On Wed, 29 Sep 2010 12:26:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It could, if we decided to punt on types with expensive constructors. AndreiOn 9/29/10 6:22 PDT, Steven Schveighoffer wrote:I'm not liking this... How many more boiler-plate functions will we be forced to add in order to support standard ranges? save() was bad enough, this is three more, when the functionality *already exists*. Can't sort just use: x = r1.front; r1.front = r2.front; r2.front = x; ??? -Stevestd.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition.
Sep 29 2010
On Wed, 29 Sep 2010 13:25:23 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 9/29/10 10:10 PDT, Steven Schveighoffer wrote:What I mean is, why is it automatically assumed that if front does not return a ref, the only way to swap is via moveX? If T == int, why must we have a moveFront to deal with it? IMO, all algorithms should default to copying unless alternatives exist. From what I understand, moveFront is going to be *more* expensive, since it has to zero out the original. While this is fine for some types, it's not fine for simple types. -SteveOn Wed, 29 Sep 2010 12:26:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It could, if we decided to punt on types with expensive constructors.On 9/29/10 6:22 PDT, Steven Schveighoffer wrote:I'm not liking this... How many more boiler-plate functions will we be forced to add in order to support standard ranges? save() was bad enough, this is three more, when the functionality *already exists*. Can't sort just use: x = r1.front; r1.front = r2.front; r2.front = x; ??? -Stevestd.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition.
Sep 29 2010
On 9/29/10 10:43 PDT, Steven Schveighoffer wrote:What I mean is, why is it automatically assumed that if front does not return a ref, the only way to swap is via moveX? If T == int, why must we have a moveFront to deal with it? IMO, all algorithms should default to copying unless alternatives exist.Good point. We should arrange things such that all types without elaborate copy constructors allow swapping by copying. Could you please bugzillize this so it's not forgotten? Thanks, Andrei
Sep 29 2010
On Wed, 29 Sep 2010 15:46:19 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 9/29/10 10:43 PDT, Steven Schveighoffer wrote:Well, this isn't exactly what I said, but it makes sense. If there is an elaborate copy constructor, then you shouldn't be calling it frequently. But then at the same time, isn't front() expected to be a fast operation? It's kind of the basis of most algorithms anyways, no? So if you build a range that returns T by value in front(), are you to not expect that people will call front() frequently? How does foreach perform on such an "elaborate copy constructor" range? I think there's a broken concept here somewhere...What I mean is, why is it automatically assumed that if front does not return a ref, the only way to swap is via moveX? If T == int, why must we have a moveFront to deal with it? IMO, all algorithms should default to copying unless alternatives exist.Good point. We should arrange things such that all types without elaborate copy constructors allow swapping by copying.Could you please bugzillize this so it's not forgotten?I will, I'll just wait a bit in case there are more responses. -Steve
Sep 29 2010
On Wednesday, September 29, 2010 12:55:40 Steven Schveighoffer wrote:On Wed, 29 Sep 2010 15:46:19 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:The real problem then is in any structs with elaborate copy constructors, isn't it? Essentially, it's foolish to put something which is expensive to copy in a situation where it's going to be copied much, if at all. So, essentially, any user who creates such a struct and then tries to use it with ranges is shooting themselves in the foot performance-wise. And Andrei thinks that this is a big enough issue to give them a way not to shoot themselves in the foot. I'm not sure that I agree, but I don't know that he's wrong either. Worrying about it is certainly complicating ranges though. - Jonathan M DavisOn 9/29/10 10:43 PDT, Steven Schveighoffer wrote:Well, this isn't exactly what I said, but it makes sense. If there is an elaborate copy constructor, then you shouldn't be calling it frequently. But then at the same time, isn't front() expected to be a fast operation? It's kind of the basis of most algorithms anyways, no? So if you build a range that returns T by value in front(), are you to not expect that people will call front() frequently? How does foreach perform on such an "elaborate copy constructor" range? I think there's a broken concept here somewhere...What I mean is, why is it automatically assumed that if front does not return a ref, the only way to swap is via moveX? If T == int, why must we have a moveFront to deal with it? IMO, all algorithms should default to copying unless alternatives exist.Good point. We should arrange things such that all types without elaborate copy constructors allow swapping by copying.
Sep 29 2010
== Quote from Andrei Alexandrescu (SeeWebsiteForEmail erdani.org)'s articleOn 9/29/10 10:43 PDT, Steven Schveighoffer wrote:This should already work (I noticed that it didn't a long time ago and checked in the fix, but I don't remember how thoroughly I tested the fix). Here's the relevant snippet from std.algorithm: void swapAt(R)(R r, size_t i1, size_t i2) { static if (is(typeof(&r[i1]))) { swap(r[i1], r[i2]); } else { if (i1 == i2) return; auto t1 = moveAt(r, i1); auto t2 = moveAt(r, i2); r[i2] = t1; r[i1] = t2; } } moveAt() simply copies if the range doesn't provide an explicit moveAt() and the element type doesn't have an elaborate copy constructor.What I mean is, why is it automatically assumed that if front does not return a ref, the only way to swap is via moveX? If T == int, why must we have a moveFront to deal with it? IMO, all algorithms should default to copying unless alternatives exist.Good point. We should arrange things such that all types without elaborate copy constructors allow swapping by copying. Could you please bugzillize this so it's not forgotten? Thanks, Andrei
Sep 29 2010
== Quote from Steven Schveighoffer (schveiguy yahoo.com)'s articleOn Wed, 29 Sep 2010 12:26:39 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:I somewhat agree, but apparently noone noticed my other post. moveFront() and friends **have default behavior** via the module level function std.range.moveFront() in most cases, and when they don't it is for a good reason. If Phobos directly calls the object's moveFront() instead of using the module level one with this default behavior, then IMHO it's **a bug**. Please read my post from ~an hour ago on this default behavior.On 9/29/10 6:22 PDT, Steven Schveighoffer wrote:I'm not liking this... How many more boiler-plate functions will we be forced to add in order to support standard ranges? save() was bad enough, this is three more, when the functionality *already exists*. Can't sort just use: x = r1.front; r1.front = r2.front; r2.front = x; ??? -Stevestd.algorithm.sort seems to require lvalue access to elements of a range, presumably so it can call swap on two elements during sorting. So while a range can technically allow changing of data, it cannot be passed to swap. e.g. struct myrange { property T front() {...} property T front(T t) {...} void popFront() {...} property bool empty() {...} myrange opSlice(size_t low, size_t hi) {...} property size_t length() {...} }Good news - you should be able to use sort on sealed ranges if they define moveFront, moveBack, and moveAt. Look e.g. at Zip, it's also sealed yet you can sort Zips no problem. This is a relatively new addition.
Sep 29 2010
On Wed, 29 Sep 2010 13:40:49 -0400, dsimcha <dsimcha yahoo.com> wrote:I somewhat agree, but apparently noone noticed my other post. moveFront() and friends **have default behavior** via the module level function std.range.moveFront() in most cases, and when they don't it is for a good reason. If Phobos directly calls the object's moveFront() instead of using the module level one with this default behavior, then IMHO it's **a bug**. Please read my post from ~an hour ago on this default behavior.I did see your other post. From reading the docs for moveFront and friends, it appears that you are supposed to leave the original in a default "empty shell" state. But that makes no sense in terms of simple types, like an int, or some POD struct. Am I wrong on this? But I agree with the gist of your post -- I should not have to define moveFront and friends if it makes no sense to. One problem I see here is, unless your range is specific to the element type, you have to deal with moveFront and friends. Because someone could use an element type that wants a moveFront-style swap. And this will almost certainly be boilerplate code. where's that std.mixins module? :) The easiest thing, and probably the most appropriate, is to just return ref from my Deque range. That avoids having to define moveFront, and sort still works with it. As far as danger of exposing internals, I'm not manually managing the memory anyways (it just uses array appending). But on a higher-level note, I feel ranges are becoming more complex than I'd like. The first time I heard of a range, it was a simple wrapper for two iterators. Soon, you might need a whole book to determine how to properly implement ranges so they fit into the correct algorithms. It would appear to be enough to just statically assert a range is a certain type, but I think you might actually have to assert that it's not other types. Duck typing is great for using libraries, but it's a pain for writing them. -Steve
Sep 29 2010
On 29/09/2010 15:22, Steven Schveighoffer wrote:I'm adding a new class to dcollections -- Deque of STL fame.Hi Steve, thank you for adding the dequeue data structure! :) since you have trouble regarding my email address .. nanali at wanadoo fr would be nice if we can discuss (and hopefully implement) container triggers and left leaning rb trees as well as skiplists as rb tree replacement/plugin data-structure. Bjoern
Sep 29 2010
On Wed, 29 Sep 2010 14:07:36 -0400, BLS <windevguy hotmail.de> wrote:On 29/09/2010 15:22, Steven Schveighoffer wrote:hehe, I haven't had any real interesting D projects to do for a while :) It seemed like a good challengeI'm adding a new class to dcollections -- Deque of STL fame.Hi Steve, thank you for adding the dequeue data structure! :)since you have trouble regarding my email address .. nanali at wanadoo frSent you a mail, hopefully it goes through.would be nice if we can discuss (and hopefully implement) container triggers and left leaning rb trees as well as skiplists as rb tree replacement/plugin data-structure.Definitely. -Steve
Sep 29 2010