Last active
December 4, 2015 22:05
-
-
Save kkirby/2c20298a5f12cabf4b6b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <map> | |
#include <string> | |
#include <iostream> | |
#include <regex> | |
#include <math.h> | |
typedef enum {PX,CH,CW,VH,VW} unitsize_t; | |
struct SizeInfo { | |
unitsize_t unit; | |
double size; | |
std::string describe(){ | |
char unitStr[3]; | |
if(unit == PX){ | |
strcpy(unitStr,"px"); | |
} | |
else if(unit == CH){ | |
strcpy(unitStr,"ch"); | |
} | |
else if(unit == CW){ | |
strcpy(unitStr,"cw"); | |
} | |
else if(unit == VH){ | |
strcpy(unitStr,"vh"); | |
} | |
else if(unit == VW){ | |
strcpy(unitStr,"vw"); | |
} | |
else { | |
strcpy(unitStr,"--"); | |
} | |
char output[255]; | |
sprintf(output,"SizeInfo: Size(%f), Unit(%s)",size,unitStr); | |
return std::string(output); | |
} | |
}; | |
struct SizeInfoMatch { | |
bool didMatch; | |
SizeInfo info; | |
std::string describe(){ | |
char output[255]; | |
sprintf(output,"SizeInfoMatch: DidMatch(%s), Info(%s)",didMatch ? "true" : "false",info.describe().c_str()); | |
return std::string(output); | |
} | |
}; | |
template <typename A,typename B> bool mapHasKey(const std::map<A,B>& map,A key){ | |
return map.find(key) != map.end(); | |
} | |
bool parseString(const char* str,SizeInfo& info){ | |
std::cmatch matches; | |
if(std::regex_match(str,matches,std::regex("^(\\d+(?:\\.\\d+)?)(px|[cv][hw])$"))){ | |
unitsize_t unit; | |
std::csub_match unitStr = matches[2]; | |
double value = std::stod(matches[1].str()); | |
if(unitStr.compare("px") == 0){ | |
unit = PX; | |
} | |
else if(unitStr.compare("ch") == 0){ | |
unit = CH; | |
} | |
else if(unitStr.compare("cw") == 0){ | |
unit = CW; | |
} | |
else if(unitStr.compare("vw") == 0){ | |
unit = VW; | |
} | |
else if(unitStr.compare("vh") == 0){ | |
unit = VH; | |
} | |
else { | |
throw "no valid unit found."; | |
} | |
info.unit = unit; | |
info.size = value; | |
return true; | |
} | |
return false; | |
} | |
template <typename A,typename B> bool parseStringIfHas(std::map<A,B> props,const char* key,SizeInfo& info){ | |
if(mapHasKey(props,key)){ | |
return parseString(props[key],info); | |
} | |
else { | |
return false; | |
} | |
} | |
class Rect { | |
public: | |
SizeInfo top; | |
SizeInfo right; | |
SizeInfo bottom; | |
SizeInfo left; | |
SizeInfo width; | |
SizeInfo height; | |
std::string describe(){ | |
char output[1024]; | |
sprintf( | |
output, | |
"Rect: Top(%s), Right(%s), Bottom(%s), Left(%s), Width(%s), Height(%s)", | |
top.describe().c_str(),right.describe().c_str(),bottom.describe().c_str(), | |
left.describe().c_str(),width.describe().c_str(),height.describe().c_str() | |
); | |
return std::string(output); | |
} | |
}; | |
class MyView : public Rect {}; | |
template <typename T,typename... Args> T ViewBuilder(std::map<const char*,const char*> props,Args... args){ | |
T instance = T(args...); | |
static_assert( | |
std::is_base_of<Rect, T>::value, | |
"T must be a descendant of Rect" | |
); | |
parseStringIfHas(props,"width",instance.width); | |
parseStringIfHas(props,"height",instance.height); | |
parseStringIfHas(props,"top",instance.top); | |
parseStringIfHas(props,"right",instance.right); | |
parseStringIfHas(props,"bottom",instance.bottom); | |
parseStringIfHas(props,"left",instance.left); | |
return instance; | |
} | |
int main(){ | |
auto view = ViewBuilder<MyView>({ | |
{"width","100.1234px"}, | |
{"height","10vw"}, | |
{"top","1024px"}, | |
{"left","10px"} | |
}); | |
std::cout << view.describe().c_str() << "\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment