Re: Emulating 'swizzling' in C++
On 18 Set, 17:17, Alan Woodland <aj...@aber.ac.uk> wrote:
Hi,
A number of 'C-style' languages define a 'swizzle' operator which allows
the permutation of the elements of vector datatypes. This is typically
done with an extra meaning to the . operator.
In C++ we can't overload operator. for fairly good reasons! Is there a
tidier way of emulating this syntax than the following:
#include <iostream>
#define zyxw swizzle(3,2,1,0)
struct ivec4 {
int data[4];
ivec4 swizzle(unsigned char p1, unsigned char p2, unsigne=
d char
p3, unsigned char p4) {
ivec4 ret;
ret.data[0] = data[p1];
ret.data[1] = data[p2];
ret.data[2] = data[p3];
ret.data[3] = data[p4];
return ret;
}
};
int main() {
ivec4 f1, f2;
f1.data[0] = -666;
f2 = f1.zyxw;
std::cout << f2.data[3] << std::endl;
return 0;
}
This has some pretty serious problems, because of the macro use (and
generating a macro like this for all possible permutations of larger
vectors is quite sizeable!)
Can anyone suggest a cleaner way to achieve this 'syntax' within the
existing (including proposed C++0x) language?
See if you like this ugly beast too:
-------
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
#define STATIC_ASSERT(expr) CompileTimeAssert<(expr)>()
string tostring(int i) {
ostringstream oss;
oss << i;
return oss.str();
}
struct vec_error {
const string msg;
vec_error(const string& s) : msg(s) {}
};
template<class T>
class vec_base {
public:
virtual size_t size() const = 0;
virtual T& operator[](int) throw(vec_error) = 0;
virtual T operator[](int) const throw(vec_error) = 0;
virtual ~vec_base() {};
};
template<char first_char, char last_char, class T>
class vec : public vec_base<T> {
vector<T> v_data;
static const int v_size = last_char - first_char + 1;
T& checked(int vi) {
if (0 <= vi && vi < v_size) {
return v_data[vi];
} else {
throw vec_error(string("index out of range: ") + tostring(vi));
}
}
const T& checked(int vi) const {
if (0 <= vi && vi < v_size) {
return v_data[vi];
} else {
throw vec_error(string("index out of range: ") + tostring(vi));
}
}
public:
vec() {
STATIC_ASSERT(v_size > 0);
v_data.resize(v_size);
}
size_t size() const {
return v_size;
}
vec operator()(const string& order) const throw(vec_error) {
if (order.size() != v_size) throw vec_error("string size error");
vec result;
for (int i = 0; i < v_size; ++i) {
try {
result.v_data[i] = checked(order[i] - first_char);
} catch (vec_error) {
throw vec_error(string("char out of range: ") + order[i]);
}
}
return result;
}
T& operator()(char ch) throw(vec_error) {
try {
return checked(ch - first_char);
} catch (vec_error) {
throw vec_error(string("char out of range: ") + ch);
}
}
T operator()(char ch) const throw(vec_error) {
try {
return checked(ch - first_char);
} catch (vec_error) {
throw vec_error(string("char out of range: ") + ch);
}
}
T& operator[](int vi) throw(vec_error) {
return checked(vi);
}
T operator[](int vi) const throw(vec_error) {
return checked(vi);
}
void detail_to(ostream& os) const {
char ch = first_char;
os << "{" << endl;
for (int i = 0; i < v_size-1; ++i) {
os << " '" << ch++ << "' == " << v_data[i] << endl;
}
os << " '" << ch << "' == " << v_data[v_size-1] << endl;
os << "}" << endl;
}
};
template<class T>
ostream& operator<<(ostream& os, const vec_base<T>& v) {
os << "{";
for (int i = 0, e = v.size()-1; i < e; ++i) {
os << v[i] << ", ";
}
os << v[v.size()-1] << "}";
return os;
}
void test() {
vec<'x', 'z', string> xz1, xz2;
xz1('x') = "roll";
xz1('y') = "pitch";
xz1('z') = "yaw";
xz2 = xz1("zxy");
cout << "xz1 == " << xz1 << endl;
cout << "xz2 == " << xz2 << endl;
vec<'a', 'f', int> af1, af2;
for (int i = 0, e = af1.size(); i < e; ++i) {
af1[i] = (i+1) * 10;
}
af2 = af1("fedcba");
cout << "af1 details:" << endl;
af1.detail_to(cout);
cout << "af2 details:" << endl;
af2.detail_to(cout);
}
int main() {
try {
test();
} catch (vec_error m) {
cout << "vec_error! " << m.msg << endl;
}
}
-------
Output:
-------
xz1 == {roll, pitch, yaw}
xz2 == {yaw, roll, pitch}
af1 details:
{
'a' == 10
'b' == 20
'c' == 30
'd' == 40
'e' == 50
'f' == 60
}
af2 details:
{
'a' == 60
'b' == 50
'c' == 40
'd' == 30
'e' == 20
'f' == 10
}
-------
Cheers,
Francesco
--
Francesco S. Carta, hobbyist
http://fscode.altervista.org