I'm designing the next generation of a framework architecture for an internal project. Essentially there is a run time system that provides an API to applications which can be loaded/unloaded on the fly.
In the framework lives a library of custom "devices" The current interface to these devices is extremely generic; think posix load/unload/read/write/etc... One of the important principles of the framework is that the Apps need to know very little about device specifics.
Unfortunately, this interface has broken down to where the application developers end up rewriting common functions in the application itself.
I'm looking for suggestions or even a place to start reading about designing framework APIs like this. What is a good set of tools that a "device" author in the framework can use to publish an interface? What is the best way to publish an interface?
Ok - a proposal - may be vastly different from what you wanted, but feedback will help home in on something useful.
For synchronous "calls" you want your app module to send an indication of the driver function required and however many arguments, then retrieve some result. That can be achieved in a generic way by have a second, distinct read/write stream over which an encoding of the function and values is transmitted. So, say the driver API includes:
string get_stuff(string x, int y, double d[]);
This is NOT code - it's text that the framework/app can print/parse and potentially use to verify that data is sent and consumed correspondingly.
The app module then writes a "call" to the driver as a stream of function identifier and inputs, followed by a read of the result (assuming the app module has same-named variables holding the desired parameter values).
driver_api << "get_stuff " << escape(x) << ' ' << y << " [" << d.size() << "] ";
for (auto i = d.begin(); i != d.end(); ++i)
driver_api << ' ' << *i;
driver_api << '\n';
std::getline(driver_api, result);
It's a little more work (half an hour?) to create a custom stream wrapper that can wrap driver_api and insert the spaces or other separators/delimiters above, support streaming of containers, and/or send the data in a binary form, letting you write a cleaner and/or faster value-oriented version of the above, something like:
(driver_api << "get_stuff" << x << y << d) >> result;
You could also write normal C++ functions to wrap the above for the app module to call:
string get_stuff(const std::string& x, int y, const std::vector<double>& d)
{
string result;
(driver_api_ << "get_stuff" << x << y << d) >> result;
return result;
}
On the driver side, you'd write matching deserialisation routines to recover the app module specified values from the stream.
For specific architectures you may be able to get libraries to allow more convenient calls to functions, utilising debug information or ABI knowledge etc, whereas the above only needs Standard C++ and can be written to be portable (with a little care if doing binary serialisation of endian values).
EDIT - example of binary serialisation (just output for now / runs but output not carefully inspected for validity / most things fixed-width but strings are NUL terminated and containers prefixed by size / doesn't send following-field type information but very easy to create a version that does):
#include <iostream>
#include <vector>
#include <winsock2.h>
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned uint32_t;
class Binary_IOStream
{
public:
Binary_IOStream(std::istream& i, std::ostream& s) : i_(i), s_(s) { }
typedef Binary_IOStream This;
This& operator<<(int8_t x) { return write(x); }
This& operator<<(int16_t x) { return write(htons(x)); }
This& operator<<(int32_t x) { return write(htonl(x)); }
This& operator<<(uint8_t x) { return write(x); }
This& operator<<(uint16_t x) { return write(htons(x)); }
This& operator<<(uint32_t x) { return write(htonl(x)); }
This& operator<<(const std::string& s)
{ s_.write(s.c_str(), s.size() + 1); // include NUL, but could size-prefix
return *this; }
This& operator<<(double x) { return write(x); }
template <typename T>
This& operator<<(const std::vector<T>& v)
{ return write_range(v.begin(), v.end()); }
template <typename Iterator>
This& write_range(Iterator begin, Iterator end)
{
operator<<(std::distance(begin, end));
while (begin != end)
operator<<(*begin++);
return *this;
}
private:
template <typename T>
This& write(const T& t)
{ s_.write((const char*)&t, sizeof t); return *this; }
std::istream& i_;
std::ostream& s_;
};
int main()
{
Binary_IOStream bs(std::cin, std::cout);
bs << ('A' << 24) + ('b' << 16) + ('c' << 8) + 'D';
bs << "hello world!";
std::vector<double> v;
v.push_back(3.14);
v.push_back(2.72);
bs << v;
}
Related
According to its author #hkaiser, here boost::spirit::hold_any is a more performant alternative to boost::any and can, for the most part, be used as a drop-in replacement for the latter. I'm interested in it since it purports to allow for easy output streaming, a feature that boost::any lacks.
While I'm able to input simple types like int into hold_any, I can't seem to get it to hold a container such as std::vector<int> for example. Here'e the code
#include <iostream>
#include <boost/spirit/home/support/detail/hold_any.hpp> // v1.79
#include <vector>
using any = boost::spirit::hold_any;
int main() {
int a1 = 1;
any v1(a1); // OK
std::cout << v1 << std::endl; // OK
std::vector<int> w2 = {5,6};
any v2(w2); // compilation error - invalid operands to binary expression ('std::basic_istream<char>' and 'std::vector<int>')
std::cout << v2 << std::endl;
}
which fails to compile with
hold_any.hpp:155:23: error: invalid operands to binary expression ('std::basic_istream<char>' and 'std::vector<int>')
i >> *static_cast<T*>(*obj);
Presumably, the std::vector<int> needs to be made istream streamable though I'm not sure how to proceed. How does one make this work?
Firstly, that advice is 12 years old. Since then std::any was even standardized. I would not assume that hold_any is still the better choice (on the contrary).
Also, note that the answer you implied contains the exact explanation:
This class has two differences if compared to boost::any:
it utilizes the small object optimization idiom and a couple of other optimization tricks, making spirit::hold_any smaller and faster than boost::any
it has the streaming operators (operator<<() and operator>>()) defined, allowing to input and output a spirit::hold_any seemlessly.
(emphasis mine)
Incidentally, the whole question was about streaming any in the first place, so the answer was on-point there.
The code further drives home the assumption:
// these functions have been added in the assumption that the embedded
// type has a corresponding operator defined, which is completely safe
// because spirit::hold_any is used only in contexts where these operators
// do exist
template <typename Char_>
friend inline std::basic_istream<Char_>&
operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
{
return obj.table->stream_in(i, &obj.object);
}
template <typename Char_>
friend inline std::basic_ostream<Char_>&
operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
{
return obj.table->stream_out(o, &obj.object);
}
So, indeed that explains the requirement. It's a bit unfortunate that the implementation is not SFINAE-ed so that you'd only run into the limitation if you used the stream_in/stream_out operations, but here we are.
I was able to make the above code work by making a generic vector std::vector<T> both output and input streamable.
#include <iostream>
#include <boost/spirit/home/support/detail/hold_any.hpp>
#include <vector>
using any = boost::spirit::hold_any;
namespace std {
// input stream
template<typename T>
std::istream& operator >> ( std::istream& ins, std::vector<T>& p ) {
size_t sz;
ins >> sz;
for ( size_t i = 0; i < sz; ++i ) {
T tmp;
ins >> tmp;
p.push_back( tmp );
}
return ins;
}
// output stream
template<typename T>
std::ostream& operator << ( std::ostream& outs, const std::vector<T>& p ) {
outs << "[";
for ( size_t i = 0; i < p.size(); ++i ) {
outs << p[i];
if ( i != p.size() - 1 )
outs << " ";
else
outs << "]";
}
return outs;
}
}
I'd appreciate any comments on how to make the above more performant. boost::iostreams perhaps?
I have the following code where I implement dispatching on runtime value to interpret the data in certain way(in this toy example data can be either uint8_t or short).
Code seems to work, but I am wondering if I can somehow microoptimize the code so that when I have a hit(processing function matches) processing is stopped (currently even if first element of tuple is a "handler" entire tuple is iterated over at runtime).
#include <boost/mp11/tuple.hpp>
#include <iostream>
uint8_t data[4] = {0,1,100,2};
template<int runtimeId, typename T>
struct kindToType{
static constexpr int id = runtimeId;
using type = T;
};
const auto print =[]<typename T> (const T* data){
if constexpr(std::is_same_v<short, std::remove_cvref_t<T>>){
const short* values = (const short*)data;
std::cout << values[0] << " " << values[1] << std::endl;
} else if constexpr(std::is_same_v<uint8_t, std::remove_cvref_t<T>>){
const uint8_t* values = (const uint8_t*)data;
std::cout << (int)values[0] << " " << (int)values[1]<< " " << (int)values[2] << " " << (int)values[3] << std::endl;;
}
};
static constexpr std::tuple<kindToType<10, uint8_t>, kindToType<11, short>> mappings{};
void dispatch(int kind){
boost::mp11::tuple_for_each(mappings, [kind]<typename Mapping>(const Mapping&) {
if (Mapping::id == kind)
{
print((typename Mapping::type*)data);
}
});
}
int main()
{
// no guarantee that kind is index like(e.g. for two values
// it can have values 47 and 1701)
dispatch(10);
dispatch(11);
}
Notes:
I can not/want to use std::variant.
I do not want to use std::map or std::unordered map(where value is std::function)
I know this is premature optimization(even 10 integer comparisons is cheap assuming handlers do nontrivial amount of work).
my handlers are unique, i.e. it is std::map like thing, not std::multimap like thing so it is fine to break;.
kind of id used for runtime values is not guaranteed to have values in [0, n-1].
I am fine with C++20 solution as long as it is implemented in at least 1 compiler.
The runtime performance of this heavily depends on the size of your tuple. You can make your own for_each_tuple implementation that does an early out when your function gets executed:
template<typename FuncTuple, typename Selector>
void tuple_for_each(FuncTuple const& funcTuple, Selector selector)
{
std::apply([selector](auto const& ...funcs)
{
(void)(selector(funcs) || ...);
}, funcTuple);
}
your dispatch would then look like this:
void dispatch(int kind)
{
tuple_for_each(mappings, [kind]<typename Mapping>(const Mapping&)
{
std::cout << "loop, ";
if (Mapping::id == kind)
{
print((typename Mapping::type*)data);
return true;
}
return false;
});
}
If you get rid of the template in your lambda and use auto instead this code will compile with C++17. We use operator short circuiting to our advantage so the compiler will provide an early out for us. Here is the full code.
Also, note that the cast (const short*)data is UB.
I want to find the number of characters that a stream formatting operation would produce without allocating memory from the heap. In C, it can be done with
int nchars = snprintf(NULL, 0, format_string, args...);
How can it be done within the ostream framework in C++?
An implementation with std::ostringstream may allocate memory from the heap:
template <class T>
int find_nchar(const T& value) {
std::ostringstream os; // may allocate memory from the heap
os << value;
return os.str().size(); // may allocate memory from the heap
}
I think I need to make a custom ostream class to achieve this. The custom ostream should respect all the formatting flags one can set for the normal std::ostream.
I am searching for a solution that only uses the C++ standard library, not boost::iostreams, for example.
Rather than a custom std::ostream it might be easier -- and perhaps more flexible -- to implement a custom std::streambuf that can then be used with any std::ostream.
#include <streambuf>
template <class CharT, class Traits = std::char_traits<CharT>>
struct counting_streambuf: std::basic_streambuf<CharT, Traits> {
using base_t = std::basic_streambuf<CharT, Traits>;
using typename base_t::char_type;
using typename base_t::int_type;
std::streamsize count = 0;
std::streamsize xsputn(const char_type* /* unused */, std::streamsize n)
override
{
count += n;
return n;
}
int_type overflow(int_type ch)
override
{
++count;
return ch;
}
};
Then use as...
#include <iostream>
int
main (int argc, char **argv)
{
using char_type = decltype(std::cout)::char_type;
counting_streambuf<char_type> csb;
/*
* Associate the counting_streambuf with std::cout whilst
* retaining a pointer to the original std::streambuf.
*/
auto *oldbuf = std::cout.rdbuf(&csb);
std::cout << "Some text goes here...\n";
/*
* Restore the original std::streambuf.
*/
std::cout.rdbuf(oldbuf);
std::cout << "output length is " << csb.count << " characters\n";
}
Running the above results in...
output length is 23 characters
Edit: The original solution didn't overload overflow. This works on Linux but not on Windows. Thanks go to Peter Dimov from Boost, who found the solution.
I have a mathy library. In this library, I have functions to manipulate hyperplanes in a simplex space, so that I can sort through them in various ways.
It turns out that these hyperplanes can represent different things in different contexts. While the math is the same, in each context the hyperplanes mean a different thing, and are associated with different data structures.
It is advantageous to me to be able to write the code to manipulate the hyperplanes once, but allowing them to handle different data structures.
Below is a simplified example that tries to explain what I am trying to do:
// Assume this struct represent my hyperplane, or whatever
// construct I want to be able to manipulate.
struct Math {
int x;
};
// Here is my function `foo` which expects a range of Math. It does
// some work on it, and re-arranges it as it is useful to me.
template <typename It>
void foo(It begin, It end) {
while (begin < end) {
--end;
if (begin->x < end->x)
std::iter_swap(begin, end);
++begin;
}
}
template <typename Range>
void foo(Range & r) {
foo(ranges::begin(r), ranges::end(r));
}
This is basically my underlying functionality, which is common for every additional class that uses my hyperplanes (or, in this case, the Math class).
Now in other parts of my library I have classes that look like this:
struct Something {
int additional_metadata;
Math contextual_name_for_math;
};
struct SomethingElse {
double other_metadata;
std::vector<int> some_other_metadata;
Math another_different_contextual_name;
};
Now I need to be able to apply foo to ranges of these classes and rearrange them based on the properties of the Math they contain. At the same time:
foo does not know the contextual name that Math has in each of these classes.
foo does not care about the additional metadata that is present.
What I would like to write is something like this:
// Create data
std::vector<Something> S{{1,{2}},{3,{4}},{5,{6}}};
// Transform data in to view of Math, so that 'foo' can work on it
auto S_as_math = S | ranges::view::transform(
// I guess I can remove the consts here, although `foo` does not
// really need to alter the values, it only shuffles things around.
[](auto const& s) -> Math const& { return s.contextual_name_for_math; }
);
// Do work inline on the view, but hopefully on the underlying S too.
foo(S_as_math);
// Print results.
for (auto s : S) {
std::cout << '(' << s.additional_metadata << ", "
<< s.contextual_name_for_math.x << ")\n";
}
std::cout << "\n";
// expected, keeps Math and associated metadata together:
//
// (5, 6)
// (3, 4)
// (1, 2)
//
// NOT WANTED, only shuffles Math with no regard for metadata:
//
// (1, 6)
// (3, 4)
// (5, 2)
Currently I am doing this by passing boost::transform_iterators to foo that extract the Math component when dereferenced, and by using a custom implementation of iter_swap inside foo which is able to know whether it is being passed a proxy iterator and always swaps the underlying originals. This achieves what I want.
I am curious whether this is possible to do using ranges-v3. Currently I am able to compile this example if I remove the consts in the lambda I use to unwrap the Something class, but then foo only shuffles the Maths without keeping them together with their metadata.
Pass your transformation function to foo, don't foo the transformed range.
template <typename It, typename UnaryFunction>
void foo(It begin, It end, UnaryFunction func) {
while (begin < end) {
--end;
if (func(*begin).x < func(*end).x)
std::iter_swap(begin, end);
++begin;
}
}
template <typename Range, typename UnaryFunction>
void foo(Range & r, UnaryFunction func) {
foo(ranges::begin(r), ranges::end(r));
}
int main()
{
std::vector<Something> S{{1,{2}},{3,{4}},{5,{6}}};
auto S_as_math = [](auto const& s) { return s.contextual_name_for_math; };
foo(S, S_as_math);
for (auto s : S) {
std::cout << '(' << s.additional_metadata << ", "
<< s.contextual_name_for_math.x << ")\n";
}
std::cout << "\n";
}
You can keep your original template or default UnaryFunction to an identity function if you are using purely Math ranges.
I want to control whether my ostream outputting of chars and unsigned char's via << writes them as characters or integers. I can't find such an option in the standard library. For now I have reverted to using multiple overloads on a set of alternative print functions
ostream& show(ostream& os, char s) { return os << static_cast<int>(s); }
ostream& show(ostream& os, unsigned char s) { return os << static_cast<int>(s); }
Is there a better way?
No, there isn't a better way. A better way would take the form of a custom stream manipulator, like std::hex. Then you could turn your integer printing off and on without having to specify it for each number. But custom manipulators operate on the stream itself, and there aren't any format flags to do what you want. I suppose you could write your own stream, but that's way more work than you're doing now.
Honestly, your best bet is to see if your text editor has functions for making static_cast<int> easier to type. I assume you'd otherwise type it a lot or you wouldn't be asking. That way someone who reads your code knows exactly what you mean (i.e., printing a char as an integer) without having to look up the definition of a custom function.
Just an update to an old post. The actual trick is using '+'. Eg:
template <typename T>
void my_super_function(T x)
{
// ...
std::cout << +x << '\n'; // promotes x to a type printable as a number, regardless of type
// ...
}
In C++11 you could do:
template <typename T>
auto promote_to_printable_integer_type(T i) -> decltype(+i)
{
return +i;
}
Credit: How can I print a char as a number? How can I print a char* so the output shows the pointer’s numeric value?
I have a suggestion based on the technique used in how do I print an unsigned char as hex in c++ using ostream?.
template <typename Char>
struct Formatter
{
Char c;
Formatter(Char _c) : c(_c) { }
bool PrintAsNumber() const
{
// implement your condition here
}
};
template <typename Char>
std::ostream& operator<<(std::ostream& o, const Formatter<Char>& _fmt)
{
if (_fmt.PrintAsNumber())
return (o << static_cast<int>(_fmt.c));
else
return (o << _fmt.c);
}
template <typename Char>
Formatter<Char> fmt(Char _c)
{
return Formatter<Char>(_c);
}
void Test()
{
char a = 66;
std::cout << fmt(a) << std::endl;
}
In C++20 you'll be able to use std::format to do this:
unsigned char uc = 42;
std::cout << std::format("{:d}", uc); // format uc as integer 42 (the default)
std::cout << std::format("{:c}", uc); // format uc as char '*' (assuming ASCII)
In the meantime you can use the {fmt} library, std::format is based on.
Disclaimer: I'm the author of {fmt} and C++20 std::format.