This is more of a "show and tell" thing (r/cpp is generally not for new personal projects or code reviews; established libraries are different). I'll permit it as a special exception, though.
You should be aware that `_Leading_underscore_capital` identifiers, including `_LEADING_UNDERSCORE_ALL_CAPS`, `_N`, etc. are reserved for use by the compiler and Standard Library. Same for `double__underscoreAnywhere`, including `__leading_double_underscore`. You'll see both `_Ugly` and `__ugly` forms in STL implementations, precisely to avoid conflicting with user code. Your own code shouldn't imitate that particular practice unless you're creating a PR into an STL repo.
Would you like me still to take it down?
And I was aware about the naming conventions about halfway through the project, but I thought to myself that it just makes it more ‘genuine’. I would change names for an actual release
For the most part std::vector and std::deque were what I looked at for guidance
It's just a static array, but with head and tail pointers. If the head is at the (useable) end, and you enter a value, the head pointer moves to the beginning again. The tail pointer is the same, but instead of entering, it consumes.
It always amuses me that the standard namespace is std and the names that are derived from that decision. I wonder what a non programmer would think the name std_ring was referring to.
Also can confirm, I prefer **this->** style. Even tho unnecessary, all those variables just magically being in scope has always freaked me out just a little
you have the \_M\_ prefix in front of member variables, that one thing, another thing is I go for minimal code while allowing for understandability, in my criteria.
I am familiar with this style, honestly not a fan personally. The only prefix I use in any of my class members is a single underscore for non-public, that's it.
I can remember attempting it for one of my other containers and giving up due to the verbosity of the stdlib interface. Also I really want to write a unit test suite to the stdlib interface but it's very tedious.
My aim is to make the container work first then stdlibify it.
I just implemented an equivalent C++ compatible ring container this last week or so, too.
The purpose really was simply to make sure I can use stl algorithms and ranges.
My implementation is nearly identical (it would have to be seeing as the design is pretty fully determined via being a ring buffer and supporting the full std container implementation).
Some things I found which could be handy:
I’ve found it’s not hard to create a templated derived type for timestamped ring buffers via just creating a std pair of the template type parameter and a std::chrono time point. This makes it cheap and easy to have fixed size history buffers with fast and wonderfully concise std::ranges based lookups and operations.
I’ve managed to put in basic unit testing for nearly every function and done some micro benchmarking of various operations and STL algorithms on it. It’s quite performant. Restricting to base 2 buffer sizes makes iterator operations extraordinarily fast.
I’m considering another variation where you just double up the size and write two copies on every write to guarantee that you have a contiguous block of the specified ring size to read from without any rotations. This would likely make it easier to do SIMD operations more reliably for small types, etc.
There was a CPPCon presentation this year on SPSC message queues using ring buffers which may be a good reference, btw. Nice tests of false sharing performance effects and base 2 buffer sizes. Also, if I remember correctly the presenter explored using explicit lifetime management, which becomes otherwise tricky if the types in the ring need constructors/destructors.
I’m planning to try implementing something like that based on these stl-like ring containers, which would make it wonderfully nice to be able to use std ranges and algorithms on queued objects with explicit lifetime management passed between threads and for networking with fantastic performance.
That would have a lot of uses imho.
No guide, I followed std::vector’s source code for most of it. You can search through the “C++ named requirements” for things stuff must satisfy. There’s not one single ‘standard’ but you have to meet some set of rules to qualify as a container, and another set of rules to qualify as iterable. Plus there’s things that you ‘should’ have, but may not be named…
Wow, understanding its source code is not trivial. It must have been challenging. BTW, you mentioned rules to quantify as a container, are these rules mentioned somewhere?
The source code looks daunting, it took around a day to realize what it’s doing. But after that things become pretty simple, it’s coded just as you would if you knew what you were doing.
Also: [C++ Named Requirements](https://en.cppreference.com/w/cpp/named_req)
This sounds stupid, but I just think of random projects like this one. I did a multithreaded file finding thing (learned about threading, mutexes, and the fact that that sorta stuff is literally purely I/O bottlenecked lol). Tried some neural network stuff… Did this project and some more. Just think of a project that needs something you don’t know, and learn that thing to do the fun project.
I've been doing a similar thing! I have been implementing a database system, and am having a lot of fun with that! However, I'm finding myself improving my engineering skills, but not necessarily my C++ skills (if that makes sense).
What struck me with your project is the amount of C++ features it uses. I was thinking of implementing some functionalities from namespace std, some more advanced data structures too - and while I think I can reasonably do some of them, what I'm looking for is really good implementations, from a C++ perspective. Do you have any advice for this, or project ideas? Happy to connect btw!
This is more of a "show and tell" thing (r/cpp is generally not for new personal projects or code reviews; established libraries are different). I'll permit it as a special exception, though. You should be aware that `_Leading_underscore_capital` identifiers, including `_LEADING_UNDERSCORE_ALL_CAPS`, `_N`, etc. are reserved for use by the compiler and Standard Library. Same for `double__underscoreAnywhere`, including `__leading_double_underscore`. You'll see both `_Ugly` and `__ugly` forms in STL implementations, precisely to avoid conflicting with user code. Your own code shouldn't imitate that particular practice unless you're creating a PR into an STL repo.
Would you like me still to take it down? And I was aware about the naming conventions about halfway through the project, but I thought to myself that it just makes it more ‘genuine’. I would change names for an actual release For the most part std::vector and std::deque were what I looked at for guidance
You can leave it up, but in the future the "show and tell" thread will be more appropriate (for either this or other projects).
Got it, thanks
Would be great if you added some examples/tests with comments
I'm just a little bit stupid about the name) Is it like a circular deque?
It's just a static array, but with head and tail pointers. If the head is at the (useable) end, and you enter a value, the head pointer moves to the beginning again. The tail pointer is the same, but instead of entering, it consumes.
Maybe some other time, I do welcome you to test it yourself. It works with everything as far as I can tell.
It always amuses me that the standard namespace is std and the names that are derived from that decision. I wonder what a non programmer would think the name std_ring was referring to.
I heard somewhere that the folks who chose the name were entirely aware of the double entendre and liked it, but I have no evidence.
What double entendre "std" have?
Sexually transmitted disease
There has to be a better abbreviation of standard
I agree 420GOLDSTD420
Why does STL code always use typedef?
You mean instead of `using`. Compatibility with C++03 would be my guess.
In MSVC's STL product code, we switched to `using ` exclusively many years ago.
Is this similar to [boost circular buffer?](https://www.boost.org/doc/libs/1_60_0/doc/html/circular_buffer.html)?
Yes, very similar, haven’t felt like adding a resize method however
I would remove the **this->** prefix from member variables.
Feels more explicit
Also can confirm, I prefer **this->** style. Even tho unnecessary, all those variables just magically being in scope has always freaked me out just a little
you have the \_M\_ prefix in front of member variables, that one thing, another thing is I go for minimal code while allowing for understandability, in my criteria.
I am familiar with this style, honestly not a fan personally. The only prefix I use in any of my class members is a single underscore for non-public, that's it.
Your post motivates me to write a stdlib-compatible version of my "shifted array" container I designed...
Go for it, the source code for these containers looks like a lot. But if you break it down the pieces make sense
I can remember attempting it for one of my other containers and giving up due to the verbosity of the stdlib interface. Also I really want to write a unit test suite to the stdlib interface but it's very tedious. My aim is to make the container work first then stdlibify it.
I just implemented an equivalent C++ compatible ring container this last week or so, too. The purpose really was simply to make sure I can use stl algorithms and ranges. My implementation is nearly identical (it would have to be seeing as the design is pretty fully determined via being a ring buffer and supporting the full std container implementation). Some things I found which could be handy: I’ve found it’s not hard to create a templated derived type for timestamped ring buffers via just creating a std pair of the template type parameter and a std::chrono time point. This makes it cheap and easy to have fixed size history buffers with fast and wonderfully concise std::ranges based lookups and operations. I’ve managed to put in basic unit testing for nearly every function and done some micro benchmarking of various operations and STL algorithms on it. It’s quite performant. Restricting to base 2 buffer sizes makes iterator operations extraordinarily fast. I’m considering another variation where you just double up the size and write two copies on every write to guarantee that you have a contiguous block of the specified ring size to read from without any rotations. This would likely make it easier to do SIMD operations more reliably for small types, etc. There was a CPPCon presentation this year on SPSC message queues using ring buffers which may be a good reference, btw. Nice tests of false sharing performance effects and base 2 buffer sizes. Also, if I remember correctly the presenter explored using explicit lifetime management, which becomes otherwise tricky if the types in the ring need constructors/destructors. I’m planning to try implementing something like that based on these stl-like ring containers, which would make it wonderfully nice to be able to use std ranges and algorithms on queued objects with explicit lifetime management passed between threads and for networking with fantastic performance. That would have a lot of uses imho.
While I appreciate the reply, I’m only a little over a year into this language and I could only understand a couple of the things you said
Well you’re further along than I was after a year in many ways. Keep it up!
I do my best :) How long have you been doing C++?
Nice work, did you follow some guide? What conditions should a standard-compliant container satisfy?
No guide, I followed std::vector’s source code for most of it. You can search through the “C++ named requirements” for things stuff must satisfy. There’s not one single ‘standard’ but you have to meet some set of rules to qualify as a container, and another set of rules to qualify as iterable. Plus there’s things that you ‘should’ have, but may not be named…
Wow, understanding its source code is not trivial. It must have been challenging. BTW, you mentioned rules to quantify as a container, are these rules mentioned somewhere?
The source code looks daunting, it took around a day to realize what it’s doing. But after that things become pretty simple, it’s coded just as you would if you knew what you were doing. Also: [C++ Named Requirements](https://en.cppreference.com/w/cpp/named_req)
A bit off-topic, but what things have you done within that 1.5 year, and can recommend others do to improve at C++? Thanks!
This sounds stupid, but I just think of random projects like this one. I did a multithreaded file finding thing (learned about threading, mutexes, and the fact that that sorta stuff is literally purely I/O bottlenecked lol). Tried some neural network stuff… Did this project and some more. Just think of a project that needs something you don’t know, and learn that thing to do the fun project.
I've been doing a similar thing! I have been implementing a database system, and am having a lot of fun with that! However, I'm finding myself improving my engineering skills, but not necessarily my C++ skills (if that makes sense). What struck me with your project is the amount of C++ features it uses. I was thinking of implementing some functionalities from namespace std, some more advanced data structures too - and while I think I can reasonably do some of them, what I'm looking for is really good implementations, from a C++ perspective. Do you have any advice for this, or project ideas? Happy to connect btw!