Hey I am trying to implement Color space logic with c++. As you may see every color space has its unique color components with its unique ranges and names, so I tried to implement a space component logic first.
template<typename T, T min, T max>
struct SpaceComponent {
static constexpr T MIN = min;
static constexpr T MAX = max;
T value;
SpaceComponent() = default;
SpaceComponent(T value) : value(static_cast<T>(value)) {
}
operator T() const {
return value > MAX ? MAX : value < MIN ? MIN : value;
}
operator SpaceComponent<T, MIN, MAX>() const {
return SpaceComponent<T, MIN, MAX>(static_cast<T>(value));
}
inline bool operator==(const SpaceComponent &other) const {
return value == other.value;
}
inline bool operator!=(const SpaceComponent &other) const {
return !(*this == other);
}
inline bool operator>(const SpaceComponent &other) const {
return value > other.value;
}
inline bool operator<(const SpaceComponent &other) const {
return !(*this > other) && *this != other;
}
inline bool operator>=(const SpaceComponent &other) const {
return !(*this < other);
}
inline bool operator<=(const SpaceComponent &other) const {
return !(*this > other);
}
inline SpaceComponent &operator=(const T &elem) {
if (value == elem) {
return *this;
}
value = static_cast<T>(elem);
return *this;
}
inline SpaceComponent &operator=(const SpaceComponent &other) {
if (*this == other) {
return *this;
}
*this = other.value;
return *this;
}
inline SpaceComponent &operator++() {
*this = static_cast<T>(++value);
return *this;
}
inline SpaceComponent &operator--() {
*this = static_cast<T>(--value);
return *this;
}
inline SpaceComponent operator+(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value + elem);
return result;
}
inline SpaceComponent operator-(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value - elem);
return result;
}
inline SpaceComponent operator*(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value * elem);
return result;
}
inline SpaceComponent operator/(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value / elem);
return result;
}
inline SpaceComponent operator+(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value + other.value);
return result;
}
inline SpaceComponent operator-(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value - other.value);
return result;
}
inline SpaceComponent operator*(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value * other.value);
return result;
}
inline SpaceComponent operator/(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value / other.value);
return result;
}
inline SpaceComponent operator+=(const T &elem) {
*this = *this + elem;
return *this;
}
inline SpaceComponent operator-=(const T &elem) {
*this = *this - elem;
return *this;
}
inline SpaceComponent operator*=(const T &elem) {
*this = *this * elem;
return *this;
}
inline SpaceComponent operator/=(const T &elem) {
*this = *this / elem;
return *this;
}
inline SpaceComponent &operator+=(const SpaceComponent &other) {
*this = *this + other;
return *this;
}
inline SpaceComponent &operator-=(const SpaceComponent &other) {
*this = *this - other;
return *this;
}
inline SpaceComponent &operator*=(const SpaceComponent &other) {
*this = *this * other;
return *this;
}
inline SpaceComponent &operator/=(const SpaceComponent &other) {
*this = *this / other;
return *this;
}
};
By this logic I can create a color component of any type I want and it will not exit it's ranges(see implementation). Note that I am keeping MIN
and MAX
statically as I do not want my space component to increase in size(imagine what will be the size of 4096x4096 image in my ram if I do so).
Then I tried to implement different spaces of colors
struct RGB {
SpaceComponent<unsigned char, 0, 255> r;
SpaceComponent<unsigned char, 0, 255> g;
SpaceComponent<unsigned char, 0, 255> b;
inline RGB operator+(const RGB &other) {
RGB rgb;
rgb.r = r + other.r;
rgb.g = g + other.g;
rgb.b = b + other.b;
return rgb;
}
};
struct ARGB {
SpaceComponent<unsigned char, 0, 255> a;
SpaceComponent<unsigned char, 0, 255> r;
SpaceComponent<unsigned char, 0, 255> g;
SpaceComponent<unsigned char, 0, 255> b;
inline ARGB operator+(const ARGB &other) {
ARGB argb;
argb.a = a + other.a;
argb.r = r + other.r;
argb.g = g + other.g;
argb.b = b + other.b;
return argb;
}
};
I stopped at this two as I realized that I need to write all operator overloading logic for all the spaces and that is huge work. I need somehow implement the operator overloading in one struct struct Space
and derive all others from that. Note I cannot have any virtual methods as any pointer to vtable
will increase the sizeof(Space)
and it will raise problems that I already mentioned.I think I need something like template meta-programming to do this (using macros is my last choice) or using some technique like CRTP, as a draft I think my Space implementation can look like this.
using RGB = Space<SpaceComponent<unsigned char,0,255> r,SpaceComponent<unsigned char,0,255> g,SpaceComponent<unsigned char,0,255> b>;
I know that it's illegal to write like this, but can I have a struct which syntax will at least be nearly similar to this? Thx in advance.
I think it is possible if all components have the same type.
We can declare Space
like this:
template <typename T, typename ...Components>
struct Space {...}
and use syntax like:
Space<unsigned char, Component<'r'>, Component<'g'>, Component<'b'>>;
where
template <char Id>
struct Component{...} // Component is just wrapper for ComponentImpl (for creation, to not duplicate types every time)
template <typename T> // your `SpaceComponent`
struct ComponentImpl{...}
Then inside Space
we can use constexpr function to fill std::array<ComponentImpl>
.
And inside operator+
just iterate through this array and sum all components.
Also we (probably) does not have to store T min, T max, we can use std::numeric_limits to get them.
UPDATE:
I wrote some prototype of this, take a look: https://godbolt.org/z/oEThae