24 return "missing input data";
26 len = strlen(input[0]);
27 for (
unsigned i = 1; i<input.size(); ++i) {
28 size_t otherLen = strlen(input[i]);
29 if (otherLen != len) {
30 return GBS_global_string(
"length mismatch in input data (%zu <> %zu)", len, otherLen);
39 const char *SaiOperator::typeName[] = {
49 case SOP_MATRIX:
return SaiMatrixTranslator::make(config);
68 void SaiTranslator::addTranslation(
const char *from,
char to) {
69 for (
size_t o = 0; from[o]; ++o) {
79 if (input.
size() != 1) {
83 const char *in = input[0];
84 size_t length = strlen(in);
86 result.resize(length);
87 for (
size_t o = 0; o<
length; ++o) {
94 void SaiTranslator::deduceTranslations(
class ConfigMapping& mapping)
const {
97 for (
int i = 0; i<256; ++i) count[i] = 0;
98 for (
int i = 1; i<256; ++i) ++count[
safeCharIndex(transtab[i])];
102 unsigned char defaultTranslation = 0;
103 for (
int i = 1; i<256; ++i) {
104 if (count[i]>maxCount) {
106 defaultTranslation = (
unsigned char)i;
113 for (
int i = 1; i<256; ++i) {
114 if (count[i]>0 && i != defaultTranslation) {
115 unsigned char transTo = (
unsigned char)i;
116 string transFrom(1, transTo);
118 for (
int j = 1; j<256; ++j) {
119 if (transtab[j] == transTo) {
120 transFrom += (
unsigned char)j;
130 string SaiTranslator::get_config()
const {
132 deduceTranslations(cfgmap);
142 const char *defTrans = cfgmap.
get_entry(
"default");
144 if (defTrans[0] && !defTrans[1]) {
145 SaiTranslator *translator =
new SaiTranslator(defTrans[0]);
150 const char *trans = cfgmap.
get_entry(entry);
153 if (trans[0] && trans[1]) {
154 translator->addTranslation(trans+1, trans[0]);
157 error =
GBS_global_string(
"invalid content '%s' in config entry '%s'", trans, entry);
169 error =
GBS_global_string(
"invalid content '%s' in config entry 'default'", defTrans);
173 error =
"missing 'default' entry";
183 std::string SaiMatrixTranslator::get_config()
const {
185 cfgmap.
set_entry(
"first", firstToIndexChar->get_config());
187 for (
size_t s = 0;
s<secondToResult.size(); ++
s) {
189 cfgmap.
set_entry(key, secondToResult[
s]->get_config());
199 if (input.
size() != 2) {
200 error =
GBS_global_string(
"matrix translator applies to a pair of SAIs only (have: %zu)", input.
size());
206 result.resize(length);
217 if (trans1.hasError()) {
218 error = trans1.getError();
221 string tindex = trans1.getValue();
222 const size_t idxCount = secondToResult.size();
224 vector<string> trans2;
225 trans2.reserve(idxCount);
234 for (
size_t i = 0; i<idxCount && !
error; ++i) {
249 for (
size_t o = 0; o<
length; ++o) {
252 result[o] = trans2[idx][o];
261 void SaiMatrixTranslator::addOperator(
const char *from,
SaiOperatorPtr to) {
262 size_t meta = secondToResult.size()+DEFAULT_INDEX_CHAR;
264 dynamic_cast<SaiTranslator*
>(&*firstToIndexChar)->addTranslation(from,
char(meta));
265 secondToResult.push_back(to);
274 const char *first = cfgmap.
get_entry(
"first");
278 SaiMatrixTranslator *smt =
new SaiMatrixTranslator;
279 smt->firstToIndexChar = product.
getValue();
281 const char *columnsStr = cfgmap.
get_entry(
"columns");
283 int columns = atoi(columnsStr);
287 for (
int c = 0; c<columns && !
error; ++c) {
289 const char *col = cfgmap.
get_entry(key.c_str());
293 smt->secondToResult.push_back(colProduct.
getValue());
305 error =
GBS_global_string(
"entry 'columns' has to be 1 or higher (have: '%s')", columnsStr);
309 error =
"missing 'columns' entry";
319 error =
"missing 'first' entry";
329 for (
size_t i = 0; i<len; ++i) {
330 bool a = inout[i]-
'0';
336 case SBO_AND: c = a && b;
break;
337 case SBO_OR: c = a || b;
break;
338 case SBO_XOR: c = a ^ b;
break;
339 case SBO_NAND: c = !(a && b);
break;
340 case SBO_NOR: c = !(a || b);
break;
344 inout[i] = c ?
'1' :
'0';
361 string result = opname[op];
364 #if defined(ASSERTION_USED)
365 const size_t rlen = result.length();
371 for (
size_t p = result.length(); p<(MAXLEN+1); ++p) {
375 result += specifyTrueChars ?
'[' :
']';
377 result += specifyTrueChars ?
']' :
'[';
388 error =
"no input string";
391 const char *space1 = strchr(fromString,
' ');
392 bool appendFrom =
true;
395 error =
"expected at least one space character";
398 int tok1len = space1-fromString;
401 for (op = 0; opname[op]; ++op) {
402 if (strncmp(opname[op], fromString, tok1len) == 0) {
413 const char *rest = space1;
414 while (rest[0] ==
' ') ++rest;
417 error =
"truncated input string";
420 bool specTrue = rest[0] ==
'[';
421 if (!specTrue && rest[0] !=
']') {
425 char *
chars = strdup(rest+1);
426 int lastPos = strlen(chars)-1;
429 error =
"character specification too short";
432 char lastExpected = rest[0] ==
'[' ?
']' :
'[';
434 if (chars[lastPos] != lastExpected) {
435 error =
GBS_global_string(
"expected character specification to be terminated by '%c' (seen '%c')", lastExpected, chars[lastPos]);
448 if (error && appendFrom) {
458 const char *rule = cfgmap.
get_entry(rulename);
482 for (
size_t r = 0; r<rule.size(); ++r) {
484 cfgmap.
set_entry(key, rule[r].to_string());
497 const size_t saiCount = input.
size();
498 const size_t ruleCount = rule.size();
501 error =
"need at least one rule in chain";
503 else if (saiCount != ruleCount) {
504 error =
GBS_global_string(
"number of input SAIs has to match number of rules (%zu <> %zu)", saiCount, ruleCount);
508 rule[0].prepare_input_data(input[0], sailen, buffer);
510 for (
size_t r = 1; r<ruleCount; ++r) {
511 char othBuf[sailen+1];
512 rule[r].prepare_input_data(input[r], sailen, othBuf);
513 rule[r].apply(buffer, othBuf, sailen);
517 for (
size_t i = 0; i<sailen; ++i) {
518 buffer[i] = outTrans[buffer[i]-
'0'];
534 const char *rulesStr = cfgmap.
get_entry(
"rules");
535 const char *out = cfgmap.
get_entry(
"out");
537 if (!rulesStr) error =
"expected 'rules' entry missing";
538 else if (!out) error =
"expected 'out' entry missing";
540 int rules = atoi(rulesStr);
541 char out0 = out[0] ? out[0] :
'-';
542 char out1 = out[0] && out[1] ? out[1] :
'x';
563 for (
int r = 1; r<rules && !
error; ++r) {
604 const char *defAci = cfgmap.
get_entry(
"aci");
610 error =
"missing 'aci' entry";
623 size_t len[input.
size()];
626 for (
int i = 0; input[i]; ++i) {
627 len[i] = strlen(input[i]);
632 error =
"no input data";
637 for (
size_t p = 0; p<maxlen && !
error; ++p) {
639 for (
int i = 0; input[i]; ++i) {
641 toAci += input[i][p];
647 size_t fromAciLen = strlen(fromAci);
648 if (fromAciLen == 1) {
652 error =
GBS_global_string(
"Expected single character result from ACI (but received %zu chars; while '%s' -> '%s')",
653 fromAciLen, toAci.c_str(), fromAci);
673 #define TEST_EXPECT_APPLY_RESULT(op,env,expected) do{ \
674 ErrorOrString result = (op)->apply(env); \
675 TEST_EXPECT(result.hasValue()); \
676 string output = result.getValue(); \
677 TEST_EXPECT_EQUAL(output, expected); \
678 TEST_EXPECT_EQUAL(output.length(), strlen((env).get_input()[0])); \
682 #define TEST_EXPECT_APPLY_FAILURE(op,env,errorPart) do{ \
683 ErrorOrString result = (op)->apply(env); \
684 TEST_EXPECT(result.hasError()); \
685 TEST_EXPECT_CONTAINS(result.getError().deliver(), errorPart); \
688 #define TEST_OPERATOR_PRODUCTION_FAILS(optype,cfg,errorPart) do{ \
689 ErrorOrSaiOperatorPtr product = SaiOperator::make(optype, cfg); \
690 TEST_EXPECT(product.hasError()); \
691 TEST_EXPECT_CONTAINS(product.getError().deliver(), errorPart); \
701 #define TEST_OCCB_COMMONCODE(op,cfgExpected) \
702 const string cfg = (op)->get_config(); \
703 TEST_EXPECT_EQUAL(cfg, cfgExpected); \
704 ErrorOrSaiOperatorPtr product = SaiOperator::make((op)->get_type(), cfg.c_str()); \
705 TEST_EXPECT(product.hasValue()); \
706 SaiOperatorPtr op_reloaded = product.getValue(); \
707 TEST_EXPECT_EQUAL(op_reloaded->get_type(), (op)->get_type()); \
708 const string cfg_reloaded = op_reloaded->get_config(); \
709 TEST_EXPECT_EQUAL(cfg_reloaded, cfg)
711 #define TEST_OP_CFG_CONV_BIJECTIVE_SIMPLE(op,cfgExpected) do{ \
712 TEST_OCCB_COMMONCODE(op,cfgExpected); \
715 #define TEST_OP_CFG_CONV_BIJECTIVE(op,cfgExpected,env) do{ \
716 TEST_OCCB_COMMONCODE(op,cfgExpected); \
717 ErrorOrString result = (op)->apply(env); \
718 ErrorOrString result_reloaded = op_reloaded->apply(env); \
719 TEST_EXPECT_EQUAL(result.hasValue(), result_reloaded.hasValue()); \
720 if (result.hasValue()) TEST_EXPECT_EQUAL(result.getValue(), result_reloaded.getValue()); \
721 else TEST_EXPECT_EQUAL(result.getError().deliver(), result_reloaded.getError().deliver()); \
724 void TEST_SaiTranslator() {
728 SaiTranslator *st1 =
new SaiTranslator(
'-');
734 input.put(
"[[..]]]]....]>>>>>].]>>>>].[<<[..[<<[....]>>]");
739 TEST_EXPECT_APPLY_RESULT(op, env,
"---------------------------------------------");
742 st1->addTranslation(
"]>",
')');
743 st1->addTranslation(
"<[",
'(');
746 TEST_EXPECT_APPLY_RESULT(op, env,
"((--))))----)))))))-))))))-((((--((((----))))");
749 input.put(
"whatever");
750 TEST_EXPECT_APPLY_FAILURE(op, env,
"translator applies to single SAI only (have: 2)");
754 TEST_OP_CFG_CONV_BIJECTIVE(op,
"default='-';trans1='(<[';trans2=')>]'", env);
757 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_TRANSLATE,
"",
"missing 'default' entry");
758 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_TRANSLATE,
"default='xxx'",
"invalid content 'xxx' in config entry 'default'");
759 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_TRANSLATE,
"default='x';trans1='z'",
"invalid content 'z' in config entry 'trans1'");
762 void TEST_SaiMatrixTranslator() {
766 SaiTranslator *st1 =
new SaiTranslator(
'.');
767 SaiMatrixTranslator *smt1 =
new SaiMatrixTranslator(st1);
773 TEST_OP_CFG_CONV_BIJECTIVE_SIMPLE(op,
"col0='default=\\'.\\'';columns='1';first='default=\\'A\\''");
776 const char *h1235 =
"..[.<<<...<<<<<[......[<<[...]>>]......[<<<<..<...<<[....]>>....>.>>>].........[<<[....]>>>]..........]>>>>.>>>>].";
777 const char *h1345 =
"..[.<<<...<<<<[........................[<.<<..<<<<<<[....]>>>>>>>.>>.]....[<[..[<<<[...]>>]...]>]......]>>>>.>>>].";
778 const char *res01 =
"..[.<<<...<<<<<[......[<<[...]>>]......[<<<<..<<<<<<[....]>>>>>>>.>>>]....[<[..[<<<[...]>>>]..]>].....]>>>>>>>>>].";
786 TEST_EXPECT_APPLY_FAILURE(op, env,
"matrix translator applies to a pair of SAIs only (have: 1)");
791 TEST_EXPECT_APPLY_FAILURE(op, env,
"length mismatch in input data (114 <> 5)");
799 } columnTranslatorConfig[] = {
800 {
".-=",
"default='?';trans1='..-=';trans2='[[';trans3=']]';trans4='<<';trans5='>>'" },
801 {
"[",
"default='?';trans1='[[.-=';trans2='<<'" },
802 {
"]",
"default='?';trans1=']].-=';trans2='>>'" },
803 {
"<",
"default='?';trans1='<<.-=['" },
804 {
">",
"default='?';trans1='>>.-=]'" },
808 for (
int t = 0; columnTranslatorConfig[t].from; ++t) {
813 smt1->addOperator(columnTranslatorConfig[t].from, translator);
817 TEST_EXPECT_APPLY_RESULT(op, env, res01);
820 TEST_OP_CFG_CONV_BIJECTIVE(op,
821 "col0='default=\\'.\\'';"
822 "col1='default=\\'?\\';trans1=\\'.-.=\\';trans2=\\'<<\\';trans3=\\'>>\\';trans4=\\'[[\\';trans5=\\']]\\'';"
823 "col2='default=\\'?\\';trans1=\\'<<\\';trans2=\\'[-.=[\\'';"
824 "col3='default=\\'?\\';trans1=\\'>>\\';trans2=\\']-.=]\\'';"
825 "col4='default=\\'?\\';trans1=\\'<-.<=[\\'';"
826 "col5='default=\\'?\\';trans1=\\'>-.=>]\\'';"
828 "first='default=\\'A\\';trans1=\\'B-.=\\';trans2=\\'C[\\';trans3=\\'D]\\';trans4=\\'E<\\';trans5=\\'F>\\''",
832 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"",
"missing 'first' entry");
833 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first=''",
"missing 'default' entry (in ''; entry 'first')");
834 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'\\''",
"invalid content '' in config entry 'default' (in 'default='''; entry 'first')");
835 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'x\\''",
"missing 'columns' entry");
836 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'x\\'';columns='0'",
"entry 'columns' has to be 1 or higher (have: '0')");
837 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'x\\'';columns='1'",
"missing 'col0' entry");
838 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'x\\'';columns='1';col0=''",
"missing 'default' entry (in ''; entry 'col0')");
839 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'x\\'';columns='2';col0='default=\\'\\''",
"invalid content '' in config entry 'default' (in 'default='''; entry 'col0')");
840 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_MATRIX,
"first='default=\\'x\\'';columns='2';col0='default=\\'y\\''",
"missing 'col1' entry");
843 void TEST_SaiBoolchainOperator() {
844 const char *inp1 =
"--xX";
845 const char *inp2 =
"-x=x";
855 TEST_EXPECT_APPLY_FAILURE(op, env,
"missing input data");
859 TEST_EXPECT_APPLY_FAILURE(op, env,
"need at least one rule in chain");
860 TEST_OP_CFG_CONV_BIJECTIVE(op,
"out='-x';rules='0'", env);
864 TEST_EXPECT_APPLY_RESULT(op, env,
"--xx");
865 TEST_OP_CFG_CONV_BIJECTIVE(op,
"out='-x';rule0='--> [xX]';rules='1'", env);
869 TEST_EXPECT_APPLY_FAILURE(op, env,
"number of input SAIs has to match number of rules (2 <> 1)");
873 const char *expected;
887 for (
int d = 0; testdata[d].expected; ++d) {
890 TEST_EXPECT_APPLY_RESULT(op, env, testdata[d].expected);
893 TEST_OP_CFG_CONV_BIJECTIVE(op,
"out='-x';rule0='--> [xX]';rule1='NAND ]-=[';rules='2'", env);
902 input.
put(
"-x-x-x-x");
903 input.
put(
"xx--xx--");
904 input.
put(
"xxxx----");
908 const char *expected;
924 for (
int d = 0; testdata2[d].expected; ++d) {
928 TEST_EXPECT_APPLY_RESULT(op, env, testdata2[d].expected);
931 TEST_OP_CFG_CONV_BIJECTIVE(op,
"out='-x';rule0='--> [xX]';rule1='NAND ]-=[';rule2='XOR ]-=[';rules='3'", env);
940 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"",
"expected 'rules' entry missing");
941 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='0'",
"expected 'out' entry missing");
942 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +'",
"expected entry 'rule0' is missing");
944 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='123'",
"expected at least one space character in '123' (during production of 'rule0')");
945 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='1 3'",
"unknown operator token '1' in '1 3' (during production of 'rule0')");
947 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='XOR '",
"truncated input string in 'XOR ' (during production of 'rule0')");
948 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='OR 3'",
"Expected '[' or ']', found '3' in 'OR 3' (during production of 'rule0')");
949 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='AND ['",
"character specification too short in 'AND [' (during production of 'rule0')");
950 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='XNOR []'",
"wrong type in 'rule0' (expected: '-->'; got: 'XNOR')");
951 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='OR ]x '",
"expected character specification to be terminated by '[' (seen ' ') in 'OR ]x ' (during production of 'rule0')");
953 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='NOR [x]'",
"wrong type in 'rule0' (expected: '-->'; got: 'NOR')");
954 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='1';out=' +';rule0='NAND ]x['",
"wrong type in 'rule0' (expected: '-->'; got: 'NAND')");
955 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='2';out=' +';rule0='--> ]x['",
"expected entry 'rule1' is missing");
956 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_BOOLCHAIN,
"rules='2';out=' +';rule0='--> ]x[';rule1='--> ]x['",
"wrong type in 'rule1' (may not be '-->')");
959 void TEST_SaiAciApplicator() {
966 const char *aci =
"minus(1)|head(1)";
973 input.
put(
"....664--2662440-44-61662664462-----4--4------662440....");
979 TEST_EXPECT_APPLY_FAILURE(&sub1, env,
"Expected single character result from ACI (but received 2 chars; while '.' -> '-1')");
983 TEST_EXPECT_APPLY_RESULT(op, env,
"----553--155133--33-50551553351-----3--3------55133-----");
985 TEST_OP_CFG_CONV_BIJECTIVE(op,
"aci='minus(1)|head(1)'", env);
991 TEST_OPERATOR_PRODUCTION_FAILS(
SOP_ACI,
"",
"missing 'aci' entry");
static ErrorOrSaiOperatorPtr make(const char *config)
GBDATA * GB_open(const char *path, const char *opent)
void put(const char *elem)
return string(buffer, length)
CONSTEXPR_INLINE unsigned char safeCharIndex(char c)
std::string get_description() const
void apply(char *inout, const char *in, size_t len) const
ErrorOr< std::string > ErrorOrString
static ErrorOrSaiBoolRulePtr makeFromConfigRule(const ConfigMapping &cfgmap, int ruleNr)
const char * GBS_global_string(const char *templat,...)
static const char * opname[]
char * ARB_strpartdup(const char *start, const char *end)
char buffer[MESSAGE_BUFFERSIZE]
GB_ERROR check_lengths_equal(size_t &len) const
GB_ERROR GB_await_error()
std::string config_string() const
static ErrorOrSaiOperatorPtr make(SaiOperatorType type, const char *config)
ErrorOrString apply(const SaiCalcEnv &calcEnv) const OVERRIDE
#define TEST_REJECT(cond)
static void error(const char *msg)
const CharPtrArray & get_input() const
std::string get_config() const OVERRIDE
SaiOperatorType get_type() const
GBDATA * get_gbmain() const
std::string get_config() const OVERRIDE
void set_entry(const std::string &entry, const std::string &value)
void addRule(const SaiBoolRule &r)
GB_ERROR parseFrom(const std::string &configString)
ErrorOrString apply(const SaiCalcEnv &calcEnv) const OVERRIDE
std::string to_string() const
const char * get_entry(const char *entry) const
SmartPtr< SaiOperator > SaiOperatorPtr
NOT4PERL char * GB_command_interpreter_in_env(const char *str, const char *commands, const GBL_call_env &callEnv)
ARB_ERROR getError() const
ErrorOr< SaiOperatorPtr > ErrorOrSaiOperatorPtr
ErrorOr< SaiBoolRulePtr > ErrorOrSaiBoolRulePtr
static ErrorOrSaiOperatorPtr make(const char *config)
#define TEST_EXPECT_EQUAL(expr, want)
static ErrorOrSaiBoolRulePtr make(const char *fromString)
void GB_close(GBDATA *gbd)
GB_write_int const char s