mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
use ADT for strings
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
a7e2fb31e3
commit
3c50508762
10 changed files with 421 additions and 201 deletions
|
@ -364,16 +364,18 @@ format * smt2_pp_environment::pp_arith_literal(app * t, bool decimal, unsigned d
|
|||
}
|
||||
|
||||
format * smt2_pp_environment::pp_string_literal(app * t) {
|
||||
std::string s;
|
||||
zstring s;
|
||||
std::string encs;
|
||||
VERIFY (get_sutil().str.is_string(t, s));
|
||||
encs = s.encode();
|
||||
std::ostringstream buffer;
|
||||
buffer << "\"";
|
||||
for (unsigned i = 0; i < s.length(); ++i) {
|
||||
if (s[i] == '\"') {
|
||||
for (unsigned i = 0; i < encs.length(); ++i) {
|
||||
if (encs[i] == '\"') {
|
||||
buffer << "\"\"";
|
||||
}
|
||||
else {
|
||||
buffer << s[i];
|
||||
buffer << encs[i];
|
||||
}
|
||||
}
|
||||
buffer << "\"";
|
||||
|
|
|
@ -121,7 +121,7 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
(a + string) + string = a + string
|
||||
*/
|
||||
br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
|
||||
std::string s1, s2;
|
||||
zstring s1, s2;
|
||||
expr* c, *d;
|
||||
bool isc1 = m_util.str.is_string(a, s1);
|
||||
bool isc2 = m_util.str.is_string(b, s2);
|
||||
|
@ -150,10 +150,10 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
|
||||
std::string b;
|
||||
zstring b;
|
||||
m_es.reset();
|
||||
m_util.str.get_concat(a, m_es);
|
||||
size_t len = 0;
|
||||
unsigned len = 0;
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < m_es.size(); ++i) {
|
||||
if (m_util.str.is_string(m_es[i], b)) {
|
||||
|
@ -189,21 +189,21 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
|
|||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_extract(expr* a, expr* b, expr* c, expr_ref& result) {
|
||||
std::string s;
|
||||
zstring s;
|
||||
rational pos, len;
|
||||
if (m_util.str.is_string(a, s) && m_autil.is_numeral(b, pos) && m_autil.is_numeral(c, len) &&
|
||||
pos.is_unsigned() && len.is_unsigned() && pos.get_unsigned() <= s.length()) {
|
||||
unsigned _pos = pos.get_unsigned();
|
||||
unsigned _len = len.get_unsigned();
|
||||
result = m_util.str.mk_string(s.substr(_pos, _len));
|
||||
result = m_util.str.mk_string(s.extract(_pos, _len));
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
||||
std::string c, d;
|
||||
zstring c, d;
|
||||
if (m_util.str.is_string(a, c) && m_util.str.is_string(b, d)) {
|
||||
result = m().mk_bool_val(0 != strstr(c.c_str(), d.c_str()));
|
||||
result = m().mk_bool_val(c.contains(d));
|
||||
return BR_DONE;
|
||||
}
|
||||
// check if subsequence of b is in a.
|
||||
|
@ -225,15 +225,12 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
|
||||
std::string c;
|
||||
zstring c;
|
||||
rational r;
|
||||
if (m_util.str.is_string(a, c) && m_autil.is_numeral(b, r) && r.is_unsigned()) {
|
||||
unsigned j = r.get_unsigned();
|
||||
if (j < c.length()) {
|
||||
char ch = c[j];
|
||||
c[0] = ch;
|
||||
c[1] = 0;
|
||||
result = m_util.str.mk_string(c);
|
||||
result = m_util.str.mk_string(c.extract(j, 1));
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
@ -241,19 +238,14 @@ br_status seq_rewriter::mk_seq_at(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) {
|
||||
std::string s1, s2;
|
||||
zstring s1, s2;
|
||||
rational r;
|
||||
bool isc1 = m_util.str.is_string(a, s1);
|
||||
bool isc2 = m_util.str.is_string(b, s2);
|
||||
|
||||
if (isc1 && isc2 && m_autil.is_numeral(c, r) && r.is_unsigned()) {
|
||||
for (unsigned i = r.get_unsigned(); i < s1.length(); ++i) {
|
||||
if (strncmp(s1.c_str() + i, s2.c_str(), s2.length()) == 0) {
|
||||
result = m_autil.mk_numeral(rational(i) - r, true);
|
||||
return BR_DONE;
|
||||
}
|
||||
}
|
||||
result = m_autil.mk_numeral(rational(-1), true);
|
||||
int idx = s1.indexof(s2, r.get_unsigned());
|
||||
result = m_autil.mk_numeral(rational(idx), true);
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_autil.is_numeral(c, r) && r.is_neg()) {
|
||||
|
@ -270,23 +262,10 @@ br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result
|
|||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result) {
|
||||
std::string s1, s2, s3;
|
||||
zstring s1, s2, s3;
|
||||
if (m_util.str.is_string(a, s1) && m_util.str.is_string(b, s2) &&
|
||||
m_util.str.is_string(c, s3)) {
|
||||
std::ostringstream buffer;
|
||||
bool can_replace = true;
|
||||
for (size_t i = 0; i < s1.length(); ) {
|
||||
if (can_replace && strncmp(s1.c_str() + i, s2.c_str(), s2.length()) == 0) {
|
||||
buffer << s3;
|
||||
i += s2.length();
|
||||
can_replace = false;
|
||||
}
|
||||
else {
|
||||
buffer << s1[i];
|
||||
++i;
|
||||
}
|
||||
}
|
||||
result = m_util.str.mk_string(buffer.str());
|
||||
result = m_util.str.mk_string(s1.replace(s2, s3));
|
||||
return BR_DONE;
|
||||
}
|
||||
if (b == c) {
|
||||
|
@ -298,15 +277,11 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu
|
|||
|
||||
br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
||||
TRACE("seq", tout << mk_pp(a, m()) << " " << mk_pp(b, m()) << "\n";);
|
||||
std::string s1, s2;
|
||||
zstring s1, s2;
|
||||
bool isc1 = m_util.str.is_string(a, s1);
|
||||
bool isc2 = m_util.str.is_string(b, s2);
|
||||
if (isc1 && isc2) {
|
||||
bool prefix = s1.length() <= s2.length();
|
||||
for (unsigned i = 0; i < s1.length() && prefix; ++i) {
|
||||
prefix = s1[i] == s2[i];
|
||||
}
|
||||
result = m().mk_bool_val(prefix);
|
||||
result = m().mk_bool_val(s1.prefixof(s2));
|
||||
return BR_DONE;
|
||||
}
|
||||
if (m_util.str.is_empty(a)) {
|
||||
|
@ -321,7 +296,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
|
||||
if (a1 != b1 && isc1 && isc2) {
|
||||
if (s1.length() <= s2.length()) {
|
||||
if (strncmp(s1.c_str(), s2.c_str(), s1.length()) == 0) {
|
||||
if (s1.prefixof(s2)) {
|
||||
if (a == a1) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
|
@ -329,10 +304,10 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
m_util.str.get_concat(a, as);
|
||||
m_util.str.get_concat(b, bs);
|
||||
SASSERT(as.size() > 1);
|
||||
s2 = std::string(s2.c_str() + s1.length(), s2.length() - s1.length());
|
||||
s2 = s2.extract(s1.length(), s2.length()-s1.length());
|
||||
bs[0] = m_util.str.mk_string(s2);
|
||||
result = m_util.str.mk_prefix(m_util.str.mk_concat(as.size()-1, as.c_ptr()+1),
|
||||
m_util.str.mk_concat(bs.size(), bs.c_ptr()));
|
||||
m_util.str.mk_concat(bs.size(), bs.c_ptr()));
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
else {
|
||||
|
@ -341,7 +316,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (strncmp(s1.c_str(), s2.c_str(), s2.length()) == 0) {
|
||||
if (s2.prefixof(s1)) {
|
||||
if (b == b1) {
|
||||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
|
@ -349,7 +324,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
|
|||
m_util.str.get_concat(a, as);
|
||||
m_util.str.get_concat(b, bs);
|
||||
SASSERT(bs.size() > 1);
|
||||
s1 = std::string(s1.c_str() + s2.length(), s1.length() - s2.length());
|
||||
s1 = s1.extract(s2.length(), s1.length() - s2.length());
|
||||
as[0] = m_util.str.mk_string(s1);
|
||||
result = m_util.str.mk_prefix(m_util.str.mk_concat(as.size(), as.c_ptr()),
|
||||
m_util.str.mk_concat(bs.size()-1, bs.c_ptr()+1));
|
||||
|
@ -396,7 +371,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
std::string s1, s2;
|
||||
zstring s1, s2;
|
||||
if (m_util.str.is_empty(a)) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
|
@ -438,21 +413,18 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
}
|
||||
if (isc1 && isc2) {
|
||||
if (s1.length() == s2.length()) {
|
||||
SASSERT(s1 != s2);
|
||||
//SASSERT(s1 != s2);
|
||||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (s1.length() < s2.length()) {
|
||||
bool suffix = true;
|
||||
for (unsigned i = 0; i < s1.length(); ++i) {
|
||||
suffix = s1[s1.length()-i-1] == s2[s2.length()-i-1];
|
||||
}
|
||||
bool suffix = s1.suffixof(s2);
|
||||
if (suffix && a1 == 0) {
|
||||
result = m().mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (suffix) {
|
||||
s2 = std::string(s2.c_str(), s2.length()-s1.length());
|
||||
s2 = s2.extract(0, s2.length()-s1.length());
|
||||
b2 = m_util.str.mk_string(s2);
|
||||
result = m_util.str.mk_suffix(a1, b1?m_util.str.mk_concat(b1, b2):b2);
|
||||
return BR_DONE;
|
||||
|
@ -468,12 +440,9 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
result = m().mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
bool suffix = true;
|
||||
for (unsigned i = 0; i < s2.length(); ++i) {
|
||||
suffix = s1[s1.length()-i-1] == s2[s2.length()-i-1];
|
||||
}
|
||||
bool suffix = s2.suffixof(s1);
|
||||
if (suffix) {
|
||||
s1 = std::string(s1.c_str(), s1.length()-s2.length());
|
||||
s1 = s1.extract(0, s1.length()-s2.length());
|
||||
a2 = m_util.str.mk_string(s1);
|
||||
result = m_util.str.mk_suffix(a1?m_util.str.mk_concat(a1, a2):a2, b1);
|
||||
return BR_DONE;
|
||||
|
@ -491,14 +460,15 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
|
|||
br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) {
|
||||
rational r;
|
||||
if (m_autil.is_numeral(a, r)) {
|
||||
result = m_util.str.mk_string(r.to_string());
|
||||
result = m_util.str.mk_string(symbol(r.to_string().c_str()));
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
|
||||
std::string s;
|
||||
if (m_util.str.is_string(a, s)) {
|
||||
zstring str;
|
||||
if (m_util.str.is_string(a, str)) {
|
||||
std::string s = str.encode();
|
||||
for (unsigned i = 0; i < s.length(); ++i) {
|
||||
if (s[i] == '-') { if (i != 0) return BR_FAILED; }
|
||||
else if ('0' <= s[i] && s[i] <= '9') continue;
|
||||
|
@ -608,13 +578,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
change = true;
|
||||
}
|
||||
// reduce strings
|
||||
std::string s1, s2;
|
||||
zstring s1, s2;
|
||||
while (head1 < m_lhs.size() &&
|
||||
head2 < m_rhs.size() &&
|
||||
m_util.str.is_string(m_lhs[head1], s1) &&
|
||||
m_util.str.is_string(m_rhs[head2], s2)) {
|
||||
size_t l = std::min(s1.length(), s2.length());
|
||||
for (size_t i = 0; i < l; ++i) {
|
||||
unsigned l = std::min(s1.length(), s2.length());
|
||||
for (unsigned i = 0; i < l; ++i) {
|
||||
if (s1[i] != s2[i]) {
|
||||
return false;
|
||||
}
|
||||
|
@ -623,14 +593,14 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
++head1;
|
||||
}
|
||||
else {
|
||||
m_lhs[head1] = m_util.str.mk_string(std::string(s1.c_str()+l,s1.length()-l));
|
||||
m_lhs[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
|
||||
trail.push_back(m_lhs[head1]);
|
||||
}
|
||||
if (l == s2.length()) {
|
||||
++head2;
|
||||
}
|
||||
else {
|
||||
m_rhs[head2] = m_util.str.mk_string(std::string(s2.c_str()+l,s2.length()-l));
|
||||
m_rhs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
|
||||
trail.push_back(m_rhs[head2]);
|
||||
}
|
||||
change = true;
|
||||
|
@ -639,8 +609,8 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
head2 < m_rhs.size() &&
|
||||
m_util.str.is_string(m_lhs.back(), s1) &&
|
||||
m_util.str.is_string(m_rhs.back(), s2)) {
|
||||
size_t l = std::min(s1.length(), s2.length());
|
||||
for (size_t i = 0; i < l; ++i) {
|
||||
unsigned l = std::min(s1.length(), s2.length());
|
||||
for (unsigned i = 0; i < l; ++i) {
|
||||
if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
|
||||
return false;
|
||||
}
|
||||
|
@ -648,11 +618,11 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
|
|||
m_lhs.pop_back();
|
||||
m_rhs.pop_back();
|
||||
if (l < s1.length()) {
|
||||
m_lhs.push_back(m_util.str.mk_string(std::string(s1.c_str(),s1.length()-l)));
|
||||
m_lhs.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
|
||||
trail.push_back(m_lhs.back());
|
||||
}
|
||||
if (l < s2.length()) {
|
||||
m_rhs.push_back(m_util.str.mk_string(std::string(s2.c_str(),s2.length()-l)));
|
||||
m_rhs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
|
||||
trail.push_back(m_rhs.back());
|
||||
}
|
||||
change = true;
|
||||
|
@ -703,7 +673,7 @@ expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
|
|||
}
|
||||
|
||||
bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs) {
|
||||
std::string s;
|
||||
zstring s;
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
if (m_util.str.is_unit(es[i])) {
|
||||
if (all) return false;
|
||||
|
@ -725,8 +695,8 @@ bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_ve
|
|||
return true;
|
||||
}
|
||||
|
||||
bool seq_rewriter::min_length(unsigned n, expr* const* es, size_t& len) {
|
||||
std::string s;
|
||||
bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
|
||||
zstring s;
|
||||
bool bounded = true;
|
||||
len = 0;
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
|
@ -749,7 +719,7 @@ bool seq_rewriter::min_length(unsigned n, expr* const* es, size_t& len) {
|
|||
bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
|
||||
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
|
||||
is_sat = true;
|
||||
size_t len1 = 0, len2 = 0;
|
||||
unsigned len1 = 0, len2 = 0;
|
||||
bool bounded1 = min_length(szl, l, len1);
|
||||
bool bounded2 = min_length(szr, r, len2);
|
||||
if (bounded1 && len1 < len2) {
|
||||
|
|
|
@ -58,7 +58,7 @@ class seq_rewriter {
|
|||
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
|
||||
bool length_constrained(unsigned n, expr* const* l, unsigned m, expr* const* r,
|
||||
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
|
||||
bool min_length(unsigned n, expr* const* es, size_t& len);
|
||||
bool min_length(unsigned n, expr* const* es, unsigned& len);
|
||||
expr* concat_non_empty(unsigned n, expr* const* es);
|
||||
|
||||
public:
|
||||
|
|
|
@ -22,6 +22,145 @@ Revision History:
|
|||
#include "ast_pp.h"
|
||||
#include <sstream>
|
||||
|
||||
zstring::zstring(encoding enc): m_encoding(enc) {}
|
||||
|
||||
zstring::zstring(char const* s, encoding enc): m_encoding(enc) {
|
||||
// TBD: epply decoding
|
||||
while (*s) {
|
||||
m_buffer.push_back(*s);
|
||||
++s;
|
||||
}
|
||||
}
|
||||
|
||||
zstring::zstring(zstring const& other) {
|
||||
m_buffer = other.m_buffer;
|
||||
m_encoding = other.m_encoding;
|
||||
}
|
||||
|
||||
zstring::zstring(unsigned num_bits, bool const* ch) {
|
||||
SASSERT(num_bits == 8 || num_bits == 16);
|
||||
m_encoding = (num_bits == 8)?ascii:unicode;
|
||||
unsigned n = 0;
|
||||
for (unsigned i = 0; i < num_bits; ++i) {
|
||||
n |= (((unsigned)ch[i]) << num_bits);
|
||||
}
|
||||
m_buffer.push_back(n);
|
||||
}
|
||||
|
||||
zstring::zstring(unsigned ch, encoding enc) {
|
||||
m_encoding = enc;
|
||||
m_buffer.push_back(ch & ((enc == ascii)?0x000000FF:0x0000FFFF));
|
||||
}
|
||||
|
||||
zstring& zstring::operator=(zstring const& other) {
|
||||
m_encoding = other.m_encoding;
|
||||
m_buffer.reset();
|
||||
m_buffer.append(other.m_buffer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
zstring zstring::replace(zstring const& src, zstring const& dst) const {
|
||||
zstring result(m_encoding);
|
||||
if (length() < src.length()) {
|
||||
return zstring(*this);
|
||||
}
|
||||
bool found = false;
|
||||
for (unsigned i = 0; i <= length() - src.length(); ++i) {
|
||||
bool eq = !found;
|
||||
for (unsigned j = 0; eq && j < src.length(); ++j) {
|
||||
eq = m_buffer[i+j] == src[j];
|
||||
}
|
||||
if (eq) {
|
||||
result.m_buffer.append(dst.m_buffer);
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
result.m_buffer.push_back(m_buffer[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string zstring::encode() const {
|
||||
// TBD apply encodings.
|
||||
SASSERT(m_encoding == ascii);
|
||||
std::ostringstream strm;
|
||||
for (unsigned i = 0; i < m_buffer.size(); ++i) {
|
||||
strm << (char)(m_buffer[i]);
|
||||
}
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
bool zstring::suffixof(zstring const& other) const {
|
||||
if (length() > other.length()) return false;
|
||||
bool suffix = true;
|
||||
for (unsigned i = 0; suffix && i < length(); ++i) {
|
||||
suffix = m_buffer[length()-i-1] == other[other.length()-i-1];
|
||||
}
|
||||
return suffix;
|
||||
}
|
||||
|
||||
bool zstring::prefixof(zstring const& other) const {
|
||||
if (length() > other.length()) return false;
|
||||
bool prefix = true;
|
||||
for (unsigned i = 0; prefix && i < length(); ++i) {
|
||||
prefix = m_buffer[i] == other[i];
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
bool zstring::contains(zstring const& other) const {
|
||||
if (other.length() > length()) return false;
|
||||
unsigned last = length() - other.length();
|
||||
bool cont = false;
|
||||
for (unsigned i = 0; !cont && i <= last; ++i) {
|
||||
cont = true;
|
||||
for (unsigned j = 0; cont && j < other.length(); ++j) {
|
||||
cont = other[j] == m_buffer[j+i];
|
||||
}
|
||||
}
|
||||
return cont;
|
||||
}
|
||||
|
||||
int zstring::indexof(zstring const& other, int offset) const {
|
||||
SASSERT(offset >= 0);
|
||||
if (offset == length()) return -1;
|
||||
if (other.length() + offset > length()) return -1;
|
||||
unsigned last = length() - other.length();
|
||||
for (unsigned i = static_cast<unsigned>(offset); i <= last; ++i) {
|
||||
bool prefix = true;
|
||||
for (unsigned j = 0; prefix && j < other.length(); ++j) {
|
||||
prefix = m_buffer[i + j] == other[j];
|
||||
}
|
||||
if (prefix) {
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
zstring zstring::extract(int offset, int len) const {
|
||||
zstring result(m_encoding);
|
||||
SASSERT(0 <= offset && 0 <= len);
|
||||
int last = std::min(offset+len, static_cast<int>(length()));
|
||||
for (int i = offset; i < last; ++i) {
|
||||
result.m_buffer.push_back(m_buffer[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
zstring zstring::operator+(zstring const& other) const {
|
||||
SASSERT(m_encoding == other.m_encoding);
|
||||
zstring result(*this);
|
||||
result.m_buffer.append(other.m_buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ostream& zstring::operator<<(std::ostream& out) const {
|
||||
return out << encode();
|
||||
}
|
||||
|
||||
|
||||
seq_decl_plugin::seq_decl_plugin(): m_init(false),
|
||||
m_stringc_sym("String"),
|
||||
m_string(0),
|
||||
|
@ -452,6 +591,14 @@ app* seq_decl_plugin::mk_string(symbol const& s) {
|
|||
return m_manager->mk_const(f);
|
||||
}
|
||||
|
||||
app* seq_decl_plugin::mk_string(zstring const& s) {
|
||||
symbol sym(s.encode().c_str());
|
||||
parameter param(sym);
|
||||
func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string,
|
||||
func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
|
||||
return m_manager->mk_const(f);
|
||||
}
|
||||
|
||||
bool seq_decl_plugin::is_value(app* e) const {
|
||||
return is_app_of(e, m_family_id, OP_STRING_CONST);
|
||||
}
|
||||
|
@ -463,6 +610,18 @@ app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort
|
|||
return m.mk_app(f, n, args);
|
||||
}
|
||||
|
||||
app* seq_util::str::mk_string(zstring const& s) { return u.seq.mk_string(s); }
|
||||
|
||||
bool seq_util::str::is_string(expr const* n, zstring& s) const {
|
||||
if (is_string(n)) {
|
||||
s = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void seq_util::str::get_concat(expr* e, ptr_vector<expr>& es) const {
|
||||
expr* e1, *e2;
|
||||
|
|
|
@ -81,6 +81,36 @@ enum seq_op_kind {
|
|||
};
|
||||
|
||||
|
||||
class zstring {
|
||||
public:
|
||||
enum encoding {
|
||||
ascii,
|
||||
unicode
|
||||
};
|
||||
private:
|
||||
buffer<unsigned> m_buffer;
|
||||
encoding m_encoding;
|
||||
public:
|
||||
zstring(encoding enc = ascii);
|
||||
zstring(char const* s, encoding enc = ascii);
|
||||
zstring(zstring const& other);
|
||||
zstring(unsigned num_bits, bool const* ch);
|
||||
zstring(unsigned ch, encoding enc = ascii);
|
||||
zstring& operator=(zstring const& other);
|
||||
zstring replace(zstring const& src, zstring const& dst) const;
|
||||
unsigned num_bits() const { return (m_encoding==ascii)?8:16; }
|
||||
std::string encode() const;
|
||||
unsigned length() const { return m_buffer.size(); }
|
||||
unsigned operator[](unsigned i) const { return m_buffer[i]; }
|
||||
bool empty() const { return m_buffer.empty(); }
|
||||
bool suffixof(zstring const& other) const;
|
||||
bool prefixof(zstring const& other) const;
|
||||
bool contains(zstring const& other) const;
|
||||
int indexof(zstring const& other, int offset) const;
|
||||
zstring extract(int lo, int hi) const;
|
||||
zstring operator+(zstring const& other) const;
|
||||
std::ostream& operator<<(std::ostream& out) const;
|
||||
};
|
||||
|
||||
class seq_decl_plugin : public decl_plugin {
|
||||
struct psig {
|
||||
|
@ -146,6 +176,7 @@ public:
|
|||
bool is_char(ast* a) const { return a == m_char; }
|
||||
|
||||
app* mk_string(symbol const& s);
|
||||
app* mk_string(zstring const& s);
|
||||
};
|
||||
|
||||
class seq_util {
|
||||
|
@ -171,14 +202,18 @@ public:
|
|||
seq_util& u;
|
||||
ast_manager& m;
|
||||
family_id m_fid;
|
||||
|
||||
app* mk_string(char const* s) { return mk_string(symbol(s)); }
|
||||
app* mk_string(std::string const& s) { return mk_string(symbol(s.c_str())); }
|
||||
|
||||
|
||||
public:
|
||||
str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {}
|
||||
|
||||
sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); }
|
||||
app* mk_empty(sort* s) { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); }
|
||||
app* mk_string(zstring const& s);
|
||||
app* mk_string(symbol const& s) { return u.seq.mk_string(s); }
|
||||
app* mk_string(char const* s) { return mk_string(symbol(s)); }
|
||||
app* mk_string(std::string const& s) { return mk_string(symbol(s.c_str())); }
|
||||
app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); }
|
||||
app* mk_concat(expr* a, expr* b, expr* c) {
|
||||
return mk_concat(mk_concat(a, b), c);
|
||||
|
@ -193,14 +228,13 @@ public:
|
|||
|
||||
|
||||
bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); }
|
||||
|
||||
bool is_string(expr const* n, std::string& s) const {
|
||||
return is_string(n) && (s = to_app(n)->get_decl()->get_parameter(0).get_symbol().str(), true);
|
||||
}
|
||||
|
||||
bool is_string(expr const* n, symbol& s) const {
|
||||
return is_string(n) && (s = to_app(n)->get_decl()->get_parameter(0).get_symbol(), true);
|
||||
}
|
||||
|
||||
bool is_string(expr const* n, zstring& s) const;
|
||||
|
||||
bool is_empty(expr const* n) const { symbol s;
|
||||
return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && *s.bare_str() == 0);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue