/*! hybrid-36 encoder: converts integer value to string result width: must be 4 (e.g. for residue sequence numbers) or 5 (e.g. for atom serial numbers) value: integer value to be converted result: pointer to char array of size width+1 or greater on return result is null-terminated return value: pointer to error message, if any, or 0 on success Example usage (from C++): char result[4+1]; const char* errmsg = hy36encode(4, 12345, result); if (errmsg) throw std::runtime_error(errmsg); */ const char* hy36encode(unsigned width, int value, char* result) { int i = value; if (width == 4U) { if (i >= -999) { if (i < 10000) { encode_pure(digits_upper(), 10U, 4U, i, result); return 0; } i -= 10000; if (i < 1213056 /* 26*36**3 */) { i += 466560 /* 10*36**3 */; encode_pure(digits_upper(), 36U, 0U, i, result); return 0; } i -= 1213056; if (i < 1213056) { i += 466560; encode_pure(digits_lower(), 36U, 0U, i, result); return 0; } } } else if (width == 5U) { if (i >= -9999) { if (i < 100000) { encode_pure(digits_upper(), 10U, 5U, i, result); return 0; } i -= 100000; if (i < 43670016 /* 26*36**4 */) { i += 16796160 /* 10*36**4 */; encode_pure(digits_upper(), 36U, 0U, i, result); return 0; } i -= 43670016; if (i < 43670016) { i += 16796160; encode_pure(digits_lower(), 36U, 0U, i, result); return 0; } } } else { fill_with_stars(width, result); return unsupported_width(); } fill_with_stars(width, result); return value_out_of_range(); }
/*! hybrid-36 decoder: converts string s to integer result width: must be 4 (e.g. for residue sequence numbers) or 5 (e.g. for atom serial numbers) s: string to be converted does not have to be null-terminated s_size: size of s must be equal to width, or an error message is returned otherwise result: integer holding the conversion result return value: pointer to error message, if any, or 0 on success Example usage (from C++): int result; const char* errmsg = hy36decode(width, "A1T5", 4, &result); if (errmsg) throw std::runtime_error(errmsg); */ const char* hy36decode(unsigned width, const char* s, unsigned s_size, int* result) { static int first_call = 1; static int digits_values_upper[128U]; static int digits_values_lower[128U]; static const char* ie_range = "internal error hy36decode: integer value out of range."; unsigned i; int di; const char* errmsg; if (first_call) { first_call = 0; for(i=0;i<128U;i++) digits_values_upper[i] = -1; for(i=0;i<128U;i++) digits_values_lower[i] = -1; for(i=0;i<36U;i++) { di = digits_upper()[i]; if (di < 0 || di > 127) { *result = 0; return ie_range; } digits_values_upper[di] = i; } for(i=0;i<36U;i++) { di = digits_lower()[i]; if (di < 0 || di > 127) { *result = 0; return ie_range; } digits_values_lower[di] = i; } } if (s_size == width) { di = s[0]; if (di >= 0 && di <= 127) { if (digits_values_upper[di] >= 10) { errmsg = decode_pure(digits_values_upper, 36U, s, s_size, result); if (errmsg == 0) { /* result - 10*36**(width-1) + 10**width */ if (width == 4U) (*result) -= 456560; else if (width == 5U) (*result) -= 16696160; else { *result = 0; return unsupported_width(); } return 0; } } else if (digits_values_lower[di] >= 10) { errmsg = decode_pure(digits_values_lower, 36U, s, s_size, result); if (errmsg == 0) { /* result + 16*36**(width-1) + 10**width */ if (width == 4U) (*result) += 756496; else if (width == 5U) (*result) += 26973856; else { *result = 0; return unsupported_width(); } return 0; } } else { errmsg = decode_pure(digits_values_upper, 10U, s, s_size, result); if (errmsg) return errmsg; if (!(width == 4U || width == 5U)) { *result = 0; return unsupported_width(); } return 0; } } } *result = 0; return invalid_number_literal(); }
/*! hybrid-36 decoder: converts string s to integer result width: must be 4 (e.g. for residue sequence numbers) or 5 (e.g. for atom serial numbers) s: string to be converted does not have to be null-terminated s_size: size of s must be equal to width, or an error message is returned otherwise result: integer holding the conversion result return value: pointer to error message, if any, or 0 on success Example usage (from C++): int result; const char* errmsg = hy36decode(width, "A1T5", 4, &result); if (errmsg) throw std::runtime_error(errmsg); */ const char* hy36decode(unsigned width, const char* s, unsigned s_size, int* result) { static const std::vector<int> digits_values_upper_vector([]() { std::vector<int> ret(128U,-1); for(unsigned i=0; i<36U; i++) { int di = digits_upper()[i]; if (di < 0 || di > 127) { plumed_error()<<"internal error hy36decode: integer value out of range"; } ret[di] = i; } return ret; }()); static const int* digits_values_upper=digits_values_upper_vector.data(); static const std::vector<int> digits_values_lower_vector([]() { std::vector<int> ret(128U,-1); for(unsigned i=0; i<36U; i++) { int di = digits_lower()[i]; if (di < 0 || di > 127) { plumed_error()<<"internal error hy36decode: integer value out of range"; } ret[di] = i; } return ret; }()); static const int* digits_values_lower=digits_values_lower_vector.data(); int di; const char* errmsg; if (s_size == width) { di = s[0]; if (di >= 0 && di <= 127) { if (digits_values_upper[di] >= 10) { errmsg = decode_pure(digits_values_upper, 36U, s, s_size, result); if (errmsg == 0) { /* result - 10*36**(width-1) + 10**width */ if (width == 4U) (*result) -= 456560; else if (width == 5U) (*result) -= 16696160; else { *result = 0; return unsupported_width(); } return 0; } } else if (digits_values_lower[di] >= 10) { errmsg = decode_pure(digits_values_lower, 36U, s, s_size, result); if (errmsg == 0) { /* result + 16*36**(width-1) + 10**width */ if (width == 4U) (*result) += 756496; else if (width == 5U) (*result) += 26973856; else { *result = 0; return unsupported_width(); } return 0; } } else { errmsg = decode_pure(digits_values_upper, 10U, s, s_size, result); if (errmsg) return errmsg; if (!(width == 4U || width == 5U)) { *result = 0; return unsupported_width(); } return 0; } } } *result = 0; return invalid_number_literal(); }