rename src/ as spot/ and use include <spot/...>

* NEWS: Mention the change.
* src/: Rename as ...
* spot/: ... this, adjust all headers to include <spot/...> instead of
"...", and adjust all Makefile.am to search headers from the top-level
directory.
* HACKING: Add conventions about #include.
* spot/sanity/style.test: Add a few more grep to catch cases
that do not follow these conventions.
* .gitignore, Makefile.am, README, bench/stutter/Makefile.am,
bench/stutter/stutter_invariance_formulas.cc,
bench/stutter/stutter_invariance_randomgraph.cc, configure.ac,
debian/rules, doc/Doxyfile.in, doc/Makefile.am,
doc/org/.dir-locals.el.in, doc/org/g++wrap.in, doc/org/init.el.in,
doc/org/tut01.org, doc/org/tut02.org, doc/org/tut03.org,
doc/org/tut10.org, doc/org/tut20.org, doc/org/tut21.org,
doc/org/tut22.org, doc/org/tut30.org, iface/ltsmin/Makefile.am,
iface/ltsmin/kripke.test, iface/ltsmin/ltsmin.cc,
iface/ltsmin/ltsmin.hh, iface/ltsmin/modelcheck.cc,
wrap/python/Makefile.am, wrap/python/ajax/spotcgi.in,
wrap/python/spot_impl.i, wrap/python/tests/ltl2tgba.py,
wrap/python/tests/randgen.py, wrap/python/tests/run.in: Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2015-12-04 19:42:23 +01:00
parent 1fddfe60ec
commit f120dd3206
529 changed files with 1308 additions and 1262 deletions

7
spot/misc/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
.deps
.libs
*.lo
*.la
_config.h

73
spot/misc/Makefile.am Normal file
View file

@ -0,0 +1,73 @@
## -*- coding: utf-8 -*-
## Copyright (C) 2011, 2012, 2013, 2014 Laboratoire de Recherche et
## Développement de l'Epita (LRDE).
## Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de
## Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
## Université Pierre et Marie Curie.
##
## This file is part of Spot, a model checking library.
##
## Spot is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## Spot is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
## License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) $(BUDDY_CPPFLAGS) \
-I$(top_builddir)/lib -I$(top_srcdir)/lib
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
miscdir = $(pkgincludedir)/misc
nodist_misc_HEADERS = _config.h
DISTCLEANFILES = _config.h
misc_HEADERS = \
bareword.hh \
bddlt.hh \
bitvect.hh \
casts.hh \
common.hh \
escape.hh \
fixpool.hh \
formater.hh \
hash.hh \
hashfunc.hh \
intvcomp.hh \
intvcmp2.hh \
location.hh \
ltstr.hh \
minato.hh \
memusage.hh \
mspool.hh \
optionmap.hh \
position.hh \
random.hh \
satsolver.hh \
timer.hh \
tmpfile.hh \
version.hh
noinst_LTLIBRARIES = libmisc.la
libmisc_la_SOURCES = \
bareword.cc \
bitvect.cc \
escape.cc \
formater.cc \
intvcomp.cc \
intvcmp2.cc \
memusage.cc \
minato.cc \
optionmap.cc \
random.cc \
satsolver.cc \
timer.cc \
tmpfile.cc \
version.cc

65
spot/misc/bareword.cc Normal file
View file

@ -0,0 +1,65 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013, 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/bareword.hh>
#include <ctype.h>
#include <spot/misc/escape.hh>
namespace spot
{
bool
is_bare_word(const char* str)
{
// Bare words cannot be empty and should start with a letter.
if (!*str
|| !(isalpha(*str) || *str == '_' || *str == '.'))
return false;
// The remaining of the word must be alphanumeric.
while (*++str)
if (!(isalnum(*str) || *str == '_' || *str == '.'))
return false;
return true;
}
std::string
quote_unless_bare_word(const std::string& str)
{
if (is_bare_word(str.c_str()))
return str;
else
return "\"" + escape_str(str) + "\"";
}
// This is for Spin 5. Spin 6 has a relaxed parser that can
// accept any parenthesized block as an atomic propoistion.
bool is_spin_ap(const char* str)
{
if (!str || !islower(*str))
return false;
while (*++str)
if (!(isalnum(*str) || *str == '_'))
return false;
return true;
}
}

53
spot/misc/bareword.hh Normal file
View file

@ -0,0 +1,53 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <string>
namespace spot
{
/// \defgroup misc_tools Miscellaneous helper functions
/// \ingroup misc_tools
/// @{
/// \brief Whether a word is bare.
///
/// Bare words should start with a letter, an underscore, or a dot,
/// and consist solely of alphanumeric characters, underscores, and
/// dots.
SPOT_API bool is_bare_word(const char* str);
/// \brief Double-quote words that are not bare.
/// \see is_bare_word
SPOT_API std::string quote_unless_bare_word(const std::string& str);
/// \brief Whether a word can be used as an atomic proposition for Spin 5.
///
/// In Spin 5 (hence in ltl2ba and ltl3ba as well) atomic
/// propositions should start with a lowercase letter, and can then
/// consist solely of alphanumeric characters and underscores.
SPOT_API bool is_spin_ap(const char* str);
/// @}
}

53
spot/misc/bddlt.hh Normal file
View file

@ -0,0 +1,53 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2014 Laboratoire de Recherche et Developpement de
// l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <bddx.h>
#include <functional>
namespace spot
{
/// \ingroup misc_tools
/// \brief Comparison functor for BDDs.
struct bdd_less_than :
public std::binary_function<const bdd&, const bdd&, bool>
{
bool
operator()(const bdd& left, const bdd& right) const
{
return left.id() < right.id();
}
};
/// \ingroup misc_tools
/// \brief Hash functor for BDDs.
struct bdd_hash :
public std::unary_function<const bdd&, size_t>
{
size_t
operator()(const bdd& b) const
{
return b.id();
}
};
}

192
spot/misc/bitvect.cc Normal file
View file

@ -0,0 +1,192 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <spot/misc/bitvect.hh>
#include <new>
#include <iostream>
#include <cmath>
#include <hashfunc.hh>
#include <cstring>
#include <climits>
namespace spot
{
namespace
{
// How many block_t do we need to store BITCOUNT bits?
size_t block_needed(size_t bitcount)
{
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t n = (bitcount + bpb - 1) / bpb;
if (n < 1)
return 1;
return n;
}
// Fowler-Noll-Vo hash parameters.
// Add specializations as needed.
template<int numbytes>
struct fnv
{
};
// Do not define the following if ULONG_MAX cannot
// hold a 64-bit value, otherwise the parser will
// choke when parsing the constants.
#if ULONG_MAX >> 31 >> 31 >> 1 > 0
// Fowler-Noll-Vo hash parameters for 64bits
template<>
struct fnv<8>
{
static unsigned long init()
{
return 14695981039346656037UL;
}
static unsigned long prime()
{
return 1099511628211UL;
}
};
#endif
// Fowler-Noll-Vo hash parameters for 32bits
template<>
struct fnv<4>
{
static unsigned long init()
{
return 2166136261UL;
}
static unsigned long prime()
{
return 16777619UL;
}
};
}
bitvect::bitvect(size_t size, size_t block_count):
size_(size),
block_count_(block_count),
storage_(&local_storage_)
{
clear_all();
}
bitvect::bitvect(size_t size, size_t block_count, bool):
size_(size),
block_count_(block_count),
storage_(&local_storage_)
{
}
bitvect* bitvect::clone() const
{
size_t n = block_needed(size_);
// Allocate some memory for the bitvect. The instance
// already contains one int of local_storage_, but
// we allocate n-1 more so that we store the table.
void* mem = operator new(sizeof(bitvect)
+ (n - 1) * sizeof(bitvect::block_t));
bitvect* res = new(mem) bitvect(size_, n, true);
memcpy(res->storage_, storage_, res->block_count_ * sizeof(block_t));
return res;
}
size_t bitvect::hash() const
{
block_t res = fnv<sizeof(block_t)>::init();
size_t i;
size_t m = used_blocks();
if (m == 0)
return res;
for (i = 0; i < m - 1; ++i)
{
res ^= storage_[i];
res *= fnv<sizeof(block_t)>::prime();
}
// Deal with the last block, that might not be fully used.
// Compute the number n of bits used in the last block.
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t n = size() % bpb;
// Use only the least n bits from storage_[i].
res ^= storage_[i] & ((1UL << n) - 1);
return res;
}
bitvect* make_bitvect(size_t bitcount)
{
size_t n = block_needed(bitcount);
// Allocate some memory for the bitvect. The instance
// already contains one int of local_storage_, but
// we allocate n-1 more so that we store the table.
void* mem = operator new(sizeof(bitvect)
+ (n - 1) * sizeof(bitvect::block_t));
return new(mem) bitvect(bitcount, n);
}
bitvect_array* make_bitvect_array(size_t bitcount, size_t vectcount)
{
size_t n = block_needed(bitcount);
// Size of one bitvect.
size_t bvsize = sizeof(bitvect) + (n - 1) * sizeof(bitvect::block_t);
// Allocate the bitvect_array with enough space at the end
// to store all bitvect instances.
void* mem = operator new(sizeof(bitvect_array) + bvsize * vectcount);
bitvect_array* bva = new(mem) bitvect_array(vectcount, bvsize);
// Initialize all the bitvect instances.
for (size_t i = 0; i < vectcount; ++i)
new(bva->storage() + i * bvsize) bitvect(bitcount, n);
return bva;
}
std::ostream& operator<<(std::ostream& os , const bitvect& v)
{
for (size_t i = 0, end = v.size(); i != end; ++i)
os << (v.get(i) ? '1' : '0');
return os;
}
std::ostream& operator<<(std::ostream& os , const bitvect_array& a)
{
size_t end = a.size();
if (end == 0)
{
os << "empty\n";
return os;
}
int w = floor(log10(end - 1)) + 1;
for (size_t i = 0; i != end; ++i)
{
os.width(w);
os << i;
os.width(1);
os << ": " << a.at(i) << '\n';
}
return os;
}
}

534
spot/misc/bitvect.hh Normal file
View file

@ -0,0 +1,534 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <iosfwd>
#include <iostream>
#include <algorithm>
namespace spot
{
/// \ingroup misc_tools
/// @{
class bitvect;
class bitvect_array;
///\brief Allocate a bit-vector of \a bitcount bits.
///
/// The resulting object should be released with <code>delete</code>.
SPOT_API bitvect* make_bitvect(size_t bitcount);
/// \brief Allocate \a vectcount bit-vectors of \a bitcount bits.
///
/// The resulting bitvect_array should be released with <code>delete</code>.
SPOT_API bitvect_array* make_bitvect_array(size_t bitcount,
size_t vectcount);
/// \brief A bit vector
class SPOT_API bitvect
{
private:
// Used by make_bitvect to construct a large bitvect in place.
bitvect(size_t size, size_t block_count);
bitvect(size_t size, size_t block_count, bool);
public:
typedef unsigned long block_t;
bitvect():
size_(0),
block_count_(1),
storage_(&local_storage_),
local_storage_(0)
{
}
bitvect(const bitvect& other):
size_(other.size_),
block_count_(1),
storage_(&local_storage_)
{
*this = other;
}
bitvect* clone() const;
void make_empty()
{
size_ = 0;
}
bitvect& operator=(const bitvect& other)
{
reserve_blocks(other.block_count_);
size_ = other.size();
for (size_t i = 0; i < block_count_; ++i)
storage_[i] = other.storage_[i];
return *this;
}
~bitvect()
{
if (storage_ != &local_storage_)
free(storage_);
}
/// Grow the bitvector to \a new_block_count blocks.
///
/// This only changes the capacity of the bitvector, not its size.
void reserve_blocks(size_t new_block_count)
{
if (new_block_count < block_count_)
return;
if (storage_ == &local_storage_)
{
block_t* new_storage_ = static_cast<block_t*>
(malloc(new_block_count * sizeof(block_t)));
for (size_t i = 0; i < block_count_; ++i)
new_storage_[i] = storage_[i];
storage_ = new_storage_;
}
else
{
storage_ = static_cast<block_t*>
(realloc(storage_, new_block_count * sizeof(block_t)));
}
block_count_ = new_block_count;
}
private:
void grow()
{
size_t new_block_count_ = (block_count_ + 1) * 7 / 5;
reserve_blocks(new_block_count_);
}
public:
size_t used_blocks() const
{
const size_t bpb = 8 * sizeof(block_t);
return (size_ + bpb - 1) / bpb;
}
/// Append one bit.
void push_back(bool val)
{
if (size() == capacity())
grow();
size_t pos = size_++;
if (val)
set(pos);
else
clear(pos);
}
/// \brief Append the lowest \a count bits of \a data.
void push_back(block_t data, unsigned count)
{
if (size() + count > capacity())
grow();
const size_t bpb = 8 * sizeof(block_t);
// Clear the higher bits.
if (count != bpb)
data &= (1UL << count) - 1;
size_t n = size() % bpb;
size_t i = size_ / bpb;
size_ += count;
if (n == 0) // Aligned on block_t boundary
{
storage_[i] = data;
}
else // Only (bpb-n) bits free in this block.
{
// Take the lower bpb-n bits of data...
block_t mask = (1UL << (bpb - n)) - 1;
block_t data1 = (data & mask) << n;
mask <<= n;
// ... write them on the higher bpb-n bits of last block.
storage_[i] = (storage_[i] & ~mask) | data1;
// Write the remaining bits in the next block.
if (bpb - n < count)
storage_[i + 1] = data >> (bpb - n);
}
}
size_t size() const
{
return size_;
}
size_t capacity() const
{
return 8 * block_count_ * sizeof(block_t);
}
size_t hash() const;
bool get(size_t pos) const
{
assert(pos < size_);
const size_t bpb = 8 * sizeof(block_t);
return storage_[pos / bpb] & (1UL << (pos % bpb));
}
void clear_all()
{
for (size_t i = 0; i < block_count_; ++i)
storage_[i] = 0;
}
bool is_fully_clear() const
{
size_t i;
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t rest = size() % bpb;
for (i = 0; i < block_count_ - !!rest; ++i)
if (storage_[i] != 0)
return false;
// The last block might not be fully used, compare only the
// relevant portion.
if (!rest)
return true;
block_t mask = (1UL << rest) - 1;
return (storage_[i] & mask) == 0;
}
bool is_fully_set() const
{
size_t i;
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t rest = size() % bpb;
for (i = 0; i < block_count_ - !!rest; ++i)
if (storage_[i] != -1UL)
return false;
if (!rest)
return true;
// The last block might not be fully used, compare only the
// relevant portion.
block_t mask = (1UL << rest) - 1;
return ((~storage_[i]) & mask) == 0;
}
void set_all()
{
for (size_t i = 0; i < block_count_; ++i)
storage_[i] = -1UL;
}
void flip_all()
{
for (size_t i = 0; i < block_count_; ++i)
storage_[i] = ~storage_[i];
}
void set(size_t pos)
{
assert(pos < size_);
const size_t bpb = 8 * sizeof(block_t);
storage_[pos / bpb] |= 1UL << (pos % bpb);
}
void clear(size_t pos)
{
assert(pos < size_);
const size_t bpb = 8 * sizeof(block_t);
storage_[pos / bpb] &= ~(1UL << (pos % bpb));
}
void flip(size_t pos)
{
assert(pos < size_);
const size_t bpb = 8 * sizeof(block_t);
storage_[pos / bpb] ^= (1UL << (pos % bpb));
}
bitvect& operator|=(const bitvect& other)
{
assert(other.size_ <= size_);
unsigned m = std::min(other.block_count_, block_count_);
for (size_t i = 0; i < m; ++i)
storage_[i] |= other.storage_[i];
return *this;
}
bitvect& operator&=(const bitvect& other)
{
assert(other.size_ <= size_);
unsigned m = std::min(other.block_count_, block_count_);
for (size_t i = 0; i < m; ++i)
storage_[i] &= other.storage_[i];
return *this;
}
bitvect& operator^=(const bitvect& other)
{
assert(other.size_ <= size_);
unsigned m = std::min(other.block_count_, block_count_);
for (size_t i = 0; i < m; ++i)
storage_[i] ^= other.storage_[i];
return *this;
}
bitvect& operator-=(const bitvect& other)
{
assert(other.block_count_ <= block_count_);
for (size_t i = 0; i < other.block_count_; ++i)
storage_[i] &= ~other.storage_[i];
return *this;
}
bool is_subset_of(const bitvect& other) const
{
assert(other.block_count_ >= block_count_);
size_t i;
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t rest = size() % bpb;
for (i = 0; i < block_count_ - !!rest; ++i)
if ((storage_[i] & other.storage_[i]) != other.storage_[i])
return false;
if (!rest)
return true;
// The last block might not be fully used, compare only the
// relevant portion.
block_t mask = (1UL << rest) - 1;
return ((storage_[i] & mask & other.storage_[i])
== (other.storage_[i] & mask));
}
bool operator==(const bitvect& other) const
{
if (other.size_ != size_)
return false;
if (size_ == 0)
return true;
size_t i;
size_t m = other.used_blocks();
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t rest = size() % bpb;
for (i = 0; i < m - !!rest; ++i)
if (storage_[i] != other.storage_[i])
return false;
if (!rest)
return true;
// The last block might not be fully used, compare only the
// relevant portion.
block_t mask = (1UL << rest) - 1;
return (storage_[i] & mask) == (other.storage_[i] & mask);
}
bool operator!=(const bitvect& other) const
{
return !(*this == other);
}
bool operator<(const bitvect& other) const
{
if (size_ != other.size_)
return size_ < other.size_;
if (size_ == 0)
return false;
size_t i;
size_t m = other.used_blocks();
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t rest = size() % bpb;
for (i = 0; i < m - !!rest; ++i)
if (storage_[i] > other.storage_[i])
return false;
if (!rest)
return true;
// The last block might not be fully used, compare only the
// relevant portion.
block_t mask = (1UL << rest) - 1;
return (storage_[i] & mask) < (other.storage_[i] & mask);
}
bool operator>=(const bitvect& other) const
{
return !(*this < other);
}
bool operator>(const bitvect& other) const
{
return other < *this;
}
bool operator<=(const bitvect& other) const
{
return !(other < *this);
}
// \brief Extract a range of bits.
//
// Build a new bit-vector using the bits from \a begin (included)
// to \a end (excluded).
bitvect* extract_range(size_t begin, size_t end)
{
assert(begin <= end);
assert(end <= size());
size_t count = end - begin;
bitvect* res = make_bitvect(count);
res->make_empty();
if (end == begin)
return res;
const size_t bpb = 8 * sizeof(bitvect::block_t);
size_t indexb = begin / bpb;
unsigned bitb = begin % bpb;
size_t indexe = (end - 1) / bpb;
if (indexb == indexe)
{
block_t data = storage_[indexb];
data >>= bitb;
res->push_back(data, count);
}
else
{
block_t data = storage_[indexb];
data >>= bitb;
res->push_back(data, bpb - bitb);
count -= bpb - bitb;
while (count >= bpb)
{
++indexb;
res->push_back(storage_[indexb], bpb);
count -= bpb;
assert(indexb != indexe || count == 0);
}
if (count > 0)
{
++indexb;
assert(indexb == indexe);
assert(count == end % bpb);
res->push_back(storage_[indexb], count);
}
}
return res;
}
friend SPOT_API bitvect*
::spot::make_bitvect(size_t bitcount);
/// Print a bitvect.
friend SPOT_API std::ostream& operator<<(std::ostream&,
const bitvect&);
private:
friend SPOT_API bitvect_array*
::spot::make_bitvect_array(size_t bitcount,
size_t vectcount);
size_t size_;
size_t block_count_;
// storage_ points to local_storage_ as long as size_ <= block_count_ * 8.
block_t* storage_;
// Keep this at the end of the structure: when make_bitvect is used,
// it may allocate more block_t at the end of this structure.
block_t local_storage_;
};
class SPOT_API bitvect_array
{
private:
/// Private constructor used by make_bitvect_array().
bitvect_array(size_t size, size_t bvsize):
size_(size),
bvsize_(bvsize)
{
}
SPOT_LOCAL bitvect_array(const bitvect_array&) = delete;
SPOT_LOCAL void operator=(const bitvect_array&) = delete;
// Extra storage has been allocated at the end of the struct.
char* storage()
{
return reinterpret_cast<char*>(this) + sizeof(*this);
}
const char* storage() const
{
return reinterpret_cast<const char*>(this) + sizeof(*this);
}
public:
~bitvect_array()
{
for (size_t i = 0; i < size_; ++i)
at(i).~bitvect();
}
/// The number of bitvect in the array.
size_t size() const
{
return size_;
}
/// Return the bit-vector at \a index.
bitvect& at(const size_t index)
{
assert(index < size_);
return *reinterpret_cast<bitvect*>(storage() + index * bvsize_);
}
void clear_all()
{
// FIXME: This could be changed into a large memset if the
// individual vectors where not allowed to be reallocated.
for (unsigned s = 0; s < size_; s++)
at(s).clear_all();
}
/// Return the bit-vector at \a index.
const bitvect& at(const size_t index) const
{
assert(index < size_);
return *reinterpret_cast<const bitvect*>(storage() + index * bvsize_);
}
friend SPOT_API bitvect_array*
::spot::make_bitvect_array(size_t bitcount,
size_t vectcount);
/// Print a bitvect_array.
friend SPOT_API std::ostream& operator<<(std::ostream&,
const bitvect_array&);
private:
size_t size_;
size_t bvsize_;
};
/// @}
}

35
spot/misc/casts.hh Normal file
View file

@ -0,0 +1,35 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
// We usually write code like
// subclass* i = down_cast<subclass*>(m);
// assert(i);
// ... use i ...
// When NDEBUG is set, the down_cast is a fast static_cast
// and the assert has no effect.
// Otherwise, the down_cast is a dynamic_cast and may return 0
// on error, which the assert catches.
#if NDEBUG
# define down_cast static_cast
#else
# define down_cast dynamic_cast
#endif

118
spot/misc/common.hh Normal file
View file

@ -0,0 +1,118 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <cstdlib>
#include <stdexcept>
#pragma once
#ifdef __GNUC__
#define SPOT_LIKELY(expr) __builtin_expect(!!(expr), 1)
#define SPOT_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
#else
#define SPOT_LIKELY(expr) (expr)
#define SPOT_UNLIKELY(expr) (expr)
#endif
#ifdef __GNUC__
#define SPOT_DEPRECATED __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define SPOT_DEPRECATED __declspec(deprecated)
#else
#define SPOT_DEPRECATED func
#endif
#if defined _WIN32 || defined __CYGWIN__
#define SPOT_HELPER_DLL_IMPORT __declspec(dllimport)
#define SPOT_HELPER_DLL_EXPORT __declspec(dllexport)
#define SPOT_HELPER_DLL_LOCAL
#else
#if __GNUC__ >= 4
#define SPOT_HELPER_DLL_IMPORT __attribute__ ((visibility ("default")))
#define SPOT_HELPER_DLL_EXPORT __attribute__ ((visibility ("default")))
#define SPOT_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define SPOT_HELPER_DLL_IMPORT
#define SPOT_HELPER_DLL_EXPORT
#define SPOT_HELPER_DLL_LOCAL
#endif
#endif
#ifdef SPOT_BUILD
#define SPOT_DLL
#endif
// SPOT_API is used for the public API symbols. It either DLL imports
// or DLL exports (or does nothing for static build) SPOT_LOCAL is
// used for non-api symbols that may occur in header files.
#ifdef SPOT_DLL
#ifdef SPOT_BUILD
#define SPOT_API SPOT_HELPER_DLL_EXPORT
#else
#define SPOT_API SPOT_HELPER_DLL_IMPORT
#endif
#define SPOT_LOCAL SPOT_HELPER_DLL_LOCAL
#else
#define SPOT_API
#define SPOT_LOCAL
#endif
#define SPOT_API_VAR extern SPOT_API
// Swig 3.0.2 does not understand 'final' when used
// at class definition.
#ifdef SWIG
#define final
#endif
// Do not use those in code, prefer SPOT_UNREACHABLE() instead.
#if defined __clang__ || defined __GNU__
# define SPOT_UNREACHABLE_BUILTIN() __builtin_unreachable()
# elif defined _MSC_VER
# define SPOT_UNREACHABLE_BUILTIN() __assume(0)
# else
# define SPOT_UNREACHABLE_BUILTIN() abort()
#endif
// The extra parentheses in assert() is so that this
// pattern is not caught by the style checker.
#define SPOT_UNREACHABLE() do { \
assert(!("unreachable code reached")); \
SPOT_UNREACHABLE_BUILTIN(); \
} while (0)
#define SPOT_UNIMPLEMENTED() throw std::runtime_error("unimplemented");
// Useful when forwarding methods such as:
// auto func(int param) SPOT_RETURN(implem_.func(param));
#define SPOT_RETURN(code) -> decltype(code) { return code; }
namespace spot
{
struct SPOT_API parse_error: public std::runtime_error
{
parse_error(const std::string& s)
: std::runtime_error(s)
{
}
};
}

162
spot/misc/escape.cc Normal file
View file

@ -0,0 +1,162 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013, 2015 Laboratoire de Recherche et Developpement de
// l'Epita (LRDE)
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <sstream>
#include <ostream>
#include <cstring>
#include <spot/misc/escape.hh>
namespace spot
{
std::ostream&
escape_rfc4180(std::ostream& os, const std::string& str)
{
for (auto i: str)
switch (i)
{
case '"':
os << "\"\"";
break;
default:
os << i;
break;
}
return os;
}
std::ostream&
escape_latex(std::ostream& os, const std::string& str)
{
for (auto i: str)
switch (i)
{
case '~':
os << "\\text{\\textasciitilde}";
break;
case '^':
os << "\\text{\\textasciicircum}";
break;
case '\\':
os << "\\text{\\textbackslash}";
break;
case '&':
case '%':
case '$':
case '#':
case '_':
case '{':
case '}':
os << '\\';
default:
os << i;
break;
}
return os;
}
std::ostream&
escape_html(std::ostream& os, const std::string& str)
{
for (auto i: str)
switch (i)
{
case '&':
os << "&amp;";
break;
case '"':
os << "&quot;";
break;
case '<':
os << "&lt;";
break;
case '>':
os << "&gt;";
break;
default:
os << i;
break;
}
return os;
}
std::ostream&
escape_str(std::ostream& os, const std::string& str)
{
for (auto i: str)
switch (i)
{
case '\\':
os << "\\\\";
break;
case '"':
os << "\\\"";
break;
case '\n':
os << "\\n";
break;
default:
os << i;
break;
}
return os;
}
std::string
escape_str(const std::string& str)
{
std::ostringstream os;
escape_str(os, str);
return os.str();
}
std::ostream&
quote_shell_string(std::ostream& os, const char* str)
{
// Single quotes are best, unless the string to quote contains one.
if (!strchr(str, '\''))
{
os << '\'' << str << '\'';
}
else
{
// In double quotes we have to escape $ ` " or \.
os << '"';
while (*str)
switch (*str)
{
case '$':
case '`':
case '"':
case '\\':
os << '\\';
// fall through
default:
os << *str++;
break;
}
os << '"';
}
return os;
}
}

73
spot/misc/escape.hh Normal file
View file

@ -0,0 +1,73 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2013, 2015 Laboratoire de Recherche et
// Developpement de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <iosfwd>
#include <string>
namespace spot
{
/// \ingroup misc_tools
/// @{
/// \brief Double characters <code>"</code> in strings.
///
/// In CSV files, as defined by RFC4180, double-quoted string that
/// contain double-quotes should simply duplicate those quotes.
SPOT_API std::ostream&
escape_rfc4180(std::ostream& os, const std::string& str);
/// \brief Escape special LaTeX characters.
///
/// The following characters are rewritten:
/// <code>& % $ # _ { } ~ ^ \\</code>
SPOT_API std::ostream&
escape_latex(std::ostream& os, const std::string& str);
/// \brief Escape special HTML characters.
///
/// The following characters are rewritten:
/// <code>&gt; &lt; &quot; &amp;</code>
SPOT_API std::ostream&
escape_html(std::ostream& os, const std::string& str);
/// \brief Escape characters <code>"</code>, <code>\\</code>, and
/// <code>\\n</code> in \a str.
SPOT_API std::ostream&
escape_str(std::ostream& os, const std::string& str);
/// \brief Escape characters <code>"</code>, <code>\\</code>, and
/// <code>\\n</code> in \a str.
SPOT_API std::string
escape_str(const std::string& str);
/// \brief Output \a str between simple quote or double quotes
///
/// Simple quotes are preferred unless \a str contains some simple
/// quotes. In that case we use double quotes and escape anything
/// that needs to be escaped.
SPOT_API std::ostream&
quote_shell_string(std::ostream& os, const char* str);
/// @}
}

112
spot/misc/fixpool.hh Normal file
View file

@ -0,0 +1,112 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE)
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <new>
#include <cstddef>
#include <cstdlib>
#include <cassert>
namespace spot
{
/// A fixed-size memory pool implementation.
class fixed_size_pool
{
public:
/// Create a pool allocating objects of \a size bytes.
fixed_size_pool(size_t size)
: freelist_(nullptr), free_start_(nullptr),
free_end_(nullptr), chunklist_(nullptr)
{
const size_t alignement = 2 * sizeof(size_t);
size_ = ((size >= sizeof(block_) ? size : sizeof(block_))
+ alignement - 1) & ~(alignement - 1);
}
/// Free any memory allocated by this pool.
~fixed_size_pool()
{
while (chunklist_)
{
chunk_* prev = chunklist_->prev;
free(chunklist_);
chunklist_ = prev;
}
}
/// Allocate \a size bytes of memory.
void*
allocate()
{
block_* f = freelist_;
// If we have free blocks available, return the first one.
if (f)
{
freelist_ = f->next;
return f;
}
// Else, create a block out of the last chunk of allocated
// memory.
// If all the last chunk has been used, allocate one more.
if (free_start_ + size_ > free_end_)
{
const size_t requested = (size_ > 128 ? size_ : 128) * 8192 - 64;
chunk_* c = reinterpret_cast<chunk_*>(malloc(requested));
if (!c)
throw std::bad_alloc();
c->prev = chunklist_;
chunklist_ = c;
free_start_ = c->data_ + size_;
free_end_ = c->data_ + requested;
}
void* res = free_start_;
free_start_ += size_;
return res;
}
/// \brief Recycle \a size bytes of memory.
///
/// Despite the name, the memory is not really deallocated in the
/// "delete" sense: it is still owned by the pool and will be
/// reused by allocate as soon as possible. The memory is only
/// freed when the pool is destroyed.
void
deallocate (const void* ptr)
{
assert(ptr);
block_* b = reinterpret_cast<block_*>(const_cast<void*>(ptr));
b->next = freelist_;
freelist_ = b;
}
private:
size_t size_;
struct block_ { block_* next; }* freelist_;
char* free_start_;
char* free_end_;
// chunk = several agglomerated blocks
union chunk_ { chunk_* prev; char data_[1]; }* chunklist_;
};
}

62
spot/misc/formater.cc Normal file
View file

@ -0,0 +1,62 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/formater.hh>
#include <iostream>
namespace spot
{
void
formater::scan(const char* fmt, std::vector<bool>& has) const
{
for (const char* pos = fmt; *pos; ++pos)
if (*pos == '%')
{
char c = *++pos;
has[c] = true;
if (!c)
break;
}
}
void
formater::prime(const char* fmt)
{
scan(fmt, has_);
}
std::ostream&
formater::format(const char* fmt)
{
for (const char* pos = fmt; *pos; ++pos)
if (*pos != '%')
{
*output_ << *pos;
}
else
{
char c = *++pos;
call_[c]->print(*output_, pos);
if (!c)
break;
}
return *output_;
}
}

200
spot/misc/formater.hh Normal file
View file

@ -0,0 +1,200 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <iostream>
#include <string>
#include <vector>
namespace spot
{
class printable
{
public:
virtual ~printable()
{
}
virtual void
print(std::ostream&, const char*) const = 0;
};
template <class T>
class printable_value: public printable
{
protected:
T val_;
public:
const T& val() const
{
return val_;
}
T& val()
{
return val_;
}
operator const T&() const
{
return val();
}
operator T&()
{
return val();
}
printable_value&
operator=(const T& new_val)
{
val_ = new_val;
return *this;
}
virtual void
print(std::ostream& os, const char*) const
{
os << val_;
}
};
/// The default callback simply writes "%c".
class printable_id: public printable
{
public:
virtual void
print(std::ostream& os, const char* x) const
{
os << '%' << *x;
}
};
/// Called by default for "%%" and "%\0".
class printable_percent: public printable
{
public:
virtual void
print(std::ostream& os, const char*) const
{
os << '%';
}
};
class SPOT_API formater
{
printable_id id;
printable_percent percent;
public:
formater()
: has_(256), call_(256, &id)
{
call_['%'] = call_[0] = &percent;
}
virtual ~formater()
{
}
/// \brief Scan the %-sequences occuring in \a fmt.
///
/// Set has['c'] for each %c in \a fmt. \a has must
/// be 256 wide.
/// @{
void
scan(const char* fmt, std::vector<bool>& has) const;
void
scan(const std::string& fmt, std::vector<bool>& has) const
{
scan(fmt.c_str(), has);
}
/// @}
/// Collect the %-sequences occurring in \a fmt.
/// @{
void
prime(const char* fmt);
void
prime(const std::string& fmt)
{
prime(fmt.c_str());
}
/// @}
/// Whether %c occurred in the primed formats.
bool
has(char c) const
{
return has_[c];
}
/// Declare a callback function for %c.
void
declare(char c, const printable* f)
{
call_[c] = f;
}
/// Remember where to output any string.
void
set_output(std::ostream& output)
{
output_ = &output;
}
/// Expand the %-sequences in \a fmt, write the result on \a output_.
std::ostream&
format(const char* fmt);
/// Expand the %-sequences in \a fmt, write the result on \a output.
std::ostream&
format(std::ostream& output, const char* fmt)
{
set_output(output);
return format(fmt);
}
/// Expand the %-sequences in \a fmt, write the result on \a output_.
std::ostream&
format(const std::string& fmt)
{
return format(fmt.c_str());
}
/// Expand the %-sequences in \a fmt, write the result on \a output.
std::ostream&
format(std::ostream& output, const std::string& fmt)
{
return format(output, fmt.c_str());
}
private:
std::vector<bool> has_;
std::vector<const printable*> call_;
protected:
std::ostream* output_;
};
}

91
spot/misc/hash.hh Normal file
View file

@ -0,0 +1,91 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2008, 2011, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de
// Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <string>
#include <functional>
#include <spot/misc/hashfunc.hh>
#include <spot/misc/_config.h>
#include <unordered_map>
#include <unordered_set>
namespace spot
{
/// \ingroup hash_funcs
/// \brief A hash function for pointers.
template <class T>
struct ptr_hash :
public std::unary_function<const T*, size_t>
{
// A default constructor is needed if the ptr_hash object is
// stored in a const member. This occur with the clang version
// installed by OS X 10.9.
ptr_hash()
{
}
size_t operator()(const T* p) const
{
return knuth32_hash(reinterpret_cast<const char*>(p)
- static_cast<const char*>(nullptr));
}
};
/// \ingroup hash_funcs
/// \brief A hash function for strings.
typedef std::hash<std::string> string_hash;
/// \ingroup hash_funcs
/// \brief A hash function that returns identity
template<typename T>
struct identity_hash:
public std::unary_function<const T&, size_t>
{
// A default constructor is needed if the string_hash object is
// stored in a const member.
identity_hash()
{
}
size_t operator()(const T& s) const
{
return s;
}
};
struct pair_hash
{
template<typename T, typename U>
std::size_t operator()(const std::pair<T, U> &p) const
{
std::hash<T> th;
std::hash<U> uh;
return wang32_hash(static_cast<size_t>(th(p.first)) ^
static_cast<size_t>(uh(p.second)));
}
};
}

66
spot/misc/hashfunc.hh Normal file
View file

@ -0,0 +1,66 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE)
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <cstddef>
namespace spot
{
/// \defgroup hash_funcs Hashing functions
/// \ingroup misc_tools
/// \ingroup hash_funcs
/// @{
/// \brief Thomas Wang's 32 bit hash function.
///
/// Hash an integer amongst the integers.
/// http://web.archive.org/web/2011/concentric.net/~Ttwang/tech/inthash.htm
inline size_t
wang32_hash(size_t key)
{
// We assume that size_t has at least 32bits.
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
/// \brief Knuth's Multiplicative hash function.
///
/// This function is suitable for hashing values whose
/// high order bits do not vary much (ex. addresses of
/// memory objects). Prefer spot::wang32_hash() otherwise.
/// http://web.archive.org/web/2011/concentric.net/~Ttwang/tech/addrhash.htm
inline size_t
knuth32_hash(size_t key)
{
// 2654435761 is the golden ratio of 2^32. The right shift of 3
// bits assumes that all objects are aligned on a 8 byte boundary.
return (key >> 3) * 2654435761U;
}
/// @}
}

551
spot/misc/intvcmp2.cc Normal file
View file

@ -0,0 +1,551 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/common.hh>
#include <cstddef>
#include <cassert>
#include <spot/misc/intvcmp2.hh>
namespace spot
{
namespace
{
// This implements integer compression inspired from "Simple-9".
//
// The first bits of an integer tell how the rest of the integer is coded:
// 00: 30 1-bit values id=0
// 01: 10 3-bit values id=1
// 10: 6 5-bit values id=2
// 1100: 4 7-bit values id=3
// 1101: 3 9-bit values (1 bit lost) id=4
// 1110: 2 14-bit values id=5
// 1111: 1 28-bit value id=6
template <class Self>
class stream_compression_base
{
public:
stream_compression_base(size_t size)
: size_(size)
{
}
void run()
{
static const unsigned bits_width[7] = { 1, 3, 5, 7, 9, 14, 28 };
static const unsigned max_count[8] = { 30, 10, 6, 4, 3, 2, 1, 0 };
static const unsigned max_allowed[8] = { 1,
(1 << 3) - 1,
(1 << 5) - 1,
(1 << 7) - 1,
(1 << 9) - 1,
(1 << 14) - 1,
(1 << 28) - 1,
-1U };
// If we have only X data to compress and they fit with the
// current bit width, the following table tells us we should
// use bits_width[count_to_level[X - 1]] to limit the number
// of trailing zeros we encode. E.g. count_to_level[5 - 1]
// is 2, which mean that 5 values should be encoded with
// bits_width[2] == 5 bits.
static const unsigned count_to_level[30] =
{
6, // 1
5, // 2
4, // 3
3, // 4
2, // 5
2, // 6
1, // 7
1, // 8
1, // 9
1, // 10
0, 0, 0, 0, 0, // 11-15
0, 0, 0, 0, 0, // 16-20
0, 0, 0, 0, 0, // 21-25
0, 0, 0, 0, 0, // 26-30
};
while (size_ > 0)
{
unsigned id = 0; // Current level in the above two tables.
unsigned curmax_allowed = max_allowed[id];
unsigned compressable = 0; // Number of integers ready to pack.
do
{
unsigned int val = self().data_at(compressable);
++compressable;
while (val > curmax_allowed)
{
curmax_allowed = max_allowed[++id];
if (compressable > max_count[id])
goto fast_encode;
}
if (compressable >= max_count[id])
goto fast_encode;
}
while (SPOT_LIKELY(compressable < size_));
assert(compressable < max_count[id]);
// Since we have less data than the current "id" allows,
// try to use more bits so we can encode faster.
id = count_to_level[compressable - 1];
if (compressable == max_count[id])
goto fast_encode;
// Slow compression for situations where we have
// compressable < max_count[id]. We can only be in
// one of the 3 first "id" (1, 3, or 5 bits);
{
assert(id <= 2);
unsigned bits = bits_width[id];
unsigned finalshifts = (max_count[id] - compressable) * bits;
size_t pos = 0;
unsigned output = self().data_at(pos);
while (--compressable)
{
output <<= bits;
output += self().data_at(++pos);
}
output <<= finalshifts;
output += id << 30;
self().push_data(output);
return;
}
fast_encode:
switch (id)
{
case 0: // 30 1-bit values
{
// This code has been tuned so that the compiler can
// efficiently encode it as a series of MOV+LEA
// instructions, without shifts. For instance
//
// output <<= 1;
// output += self().data_at(4);
//
// translates to (assuming %eax points to the input,
// and %edx holds the output) the following:
//
// mov ecx, [eax+16]
// lea edx, [ecx+edx*2]
//
// This optimization is the reason why we use 'output +='
// instead of the more intuitive 'output |=' everywhere in
// this file.
unsigned int output = 0x00 << 1; // 00
output += self().data_at(0);
output <<= 1;
output += self().data_at(1);
output <<= 1;
output += self().data_at(2);
output <<= 1;
output += self().data_at(3);
output <<= 1;
output += self().data_at(4);
output <<= 1;
output += self().data_at(5);
output <<= 1;
output += self().data_at(6);
output <<= 1;
output += self().data_at(7);
output <<= 1;
output += self().data_at(8);
output <<= 1;
output += self().data_at(9);
output <<= 1;
output += self().data_at(10);
output <<= 1;
output += self().data_at(11);
output <<= 1;
output += self().data_at(12);
output <<= 1;
output += self().data_at(13);
output <<= 1;
output += self().data_at(14);
output <<= 1;
output += self().data_at(15);
output <<= 1;
output += self().data_at(16);
output <<= 1;
output += self().data_at(17);
output <<= 1;
output += self().data_at(18);
output <<= 1;
output += self().data_at(19);
output <<= 1;
output += self().data_at(20);
output <<= 1;
output += self().data_at(21);
output <<= 1;
output += self().data_at(22);
output <<= 1;
output += self().data_at(23);
output <<= 1;
output += self().data_at(24);
output <<= 1;
output += self().data_at(25);
output <<= 1;
output += self().data_at(26);
output <<= 1;
output += self().data_at(27);
output <<= 1;
output += self().data_at(28);
output <<= 1;
output += self().data_at(29);
self().push_data(output);
}
break;
case 1: // 10 3-bit values
{
// This code has been tuned so that the compiler can
// efficiently encode it as a series of MOV+LEA
// instructions, without shifts. For instance
//
// output <<= 3;
// output += self().data_at(4);
//
// translates to (assuming %eax points to the input,
// and %edx holds the output) the following:
//
// mov ecx, [eax+16]
// lea edx, [ecx+edx*8]
unsigned int output = 0x01 << 3; // 01
output += self().data_at(0);
output <<= 3;
output += self().data_at(1);
output <<= 3;
output += self().data_at(2);
output <<= 3;
output += self().data_at(3);
output <<= 3;
output += self().data_at(4);
output <<= 3;
output += self().data_at(5);
output <<= 3;
output += self().data_at(6);
output <<= 3;
output += self().data_at(7);
output <<= 3;
output += self().data_at(8);
output <<= 3;
output += self().data_at(9);
self().push_data(output);
}
break;
case 2: // 6 5-bit values
{
unsigned int output = 0x02U << 30; // 10
output += self().data_at(0) << 25;
output += self().data_at(1) << 20;
output += self().data_at(2) << 15;
output += self().data_at(3) << 10;
output += self().data_at(4) << 5;
output += self().data_at(5);
self().push_data(output);
}
break;
case 3: // 4 7-bit values
{
unsigned int output = 0x0CU << 28; // 1100
output += self().data_at(0) << 21;
output += self().data_at(1) << 14;
output += self().data_at(2) << 7;
output += self().data_at(3);
self().push_data(output);
}
break;
case 4: // 3 9-bit values
{
unsigned int output = 0x0DU << 28; // 1101x (1 bit lost)
output += self().data_at(0) << 18;
output += self().data_at(1) << 9;
output += self().data_at(2);
self().push_data(output);
}
break;
case 5: // 2 14-bit values
{
unsigned int output = 0x0EU << 28; // 1110
output += self().data_at(0) << 14;
output += self().data_at(1);
self().push_data(output);
}
break;
case 6: // one 28-bit value
{
unsigned int output = 0x0FU << 28; // 1111
output += self().data_at(0);
self().push_data(output);
}
break;
}
self().forward(max_count[id]);
size_ -= max_count[id];
}
}
protected:
size_t size_;
Self& self()
{
return static_cast<Self&>(*this);
}
const Self& self() const
{
return static_cast<const Self&>(*this);
}
};
class int_array_array_compression:
public stream_compression_base<int_array_array_compression>
{
public:
int_array_array_compression(const int* array, size_t n,
int* dest, size_t& dest_n)
: stream_compression_base<int_array_array_compression>(n),
array_(array), result_size_(dest_n),
result_(dest), result_end_(dest + dest_n)
{
result_size_ = 0; // this resets dest_n.
}
void push_data(unsigned int i)
{
assert(result_ < result_end_);
++result_size_;
*result_++ = static_cast<int>(i);
}
unsigned int data_at(size_t offset)
{
return static_cast<unsigned int>(array_[offset]);
}
void forward(size_t offset)
{
array_ += offset;
}
protected:
const int* array_;
size_t& result_size_;
int* result_;
int* result_end_;
};
} // anonymous
void
int_array_array_compress2(const int* array, size_t n,
int* dest, size_t& dest_size)
{
int_array_array_compression c(array, n, dest, dest_size);
c.run();
}
namespace
{
template<class Self>
class stream_decompression_base
{
public:
void run()
{
while (SPOT_LIKELY(self().have_comp_data()))
{
unsigned val = self().next_comp_data();
unsigned id = val >> 28;
switch (id)
{
case 0x00: // 00xx - 30 1-bit values.
case 0x01:
case 0x02:
case 0x03:
self().write_data_at(0, !!(val & (1 << 29)));
self().write_data_at(1, !!(val & (1 << 28)));
self().write_data_at(2, !!(val & (1 << 27)));
self().write_data_at(3, !!(val & (1 << 26)));
self().write_data_at(4, !!(val & (1 << 25)));
self().write_data_at(5, !!(val & (1 << 24)));
self().write_data_at(6, !!(val & (1 << 23)));
self().write_data_at(7, !!(val & (1 << 22)));
self().write_data_at(8, !!(val & (1 << 21)));
self().write_data_at(9, !!(val & (1 << 20)));
self().write_data_at(10, !!(val & (1 << 19)));
self().write_data_at(11, !!(val & (1 << 18)));
self().write_data_at(12, !!(val & (1 << 17)));
self().write_data_at(13, !!(val & (1 << 16)));
self().write_data_at(14, !!(val & (1 << 15)));
self().write_data_at(15, !!(val & (1 << 14)));
self().write_data_at(16, !!(val & (1 << 13)));
self().write_data_at(17, !!(val & (1 << 12)));
self().write_data_at(18, !!(val & (1 << 11)));
self().write_data_at(19, !!(val & (1 << 10)));
self().write_data_at(20, !!(val & (1 << 9)));
self().write_data_at(21, !!(val & (1 << 8)));
self().write_data_at(22, !!(val & (1 << 7)));
self().write_data_at(23, !!(val & (1 << 6)));
self().write_data_at(24, !!(val & (1 << 5)));
self().write_data_at(25, !!(val & (1 << 4)));
self().write_data_at(26, !!(val & (1 << 3)));
self().write_data_at(27, !!(val & (1 << 2)));
self().write_data_at(28, !!(val & (1 << 1)));
self().write_data_at(29, !!(val & (1 << 0)));
self().forward(30);
break;
case 0x04: // 01xx - 10 3-bit values.
case 0x05:
case 0x06:
case 0x07:
self().write_data_at(0, (val >> 27) & 0x07);
self().write_data_at(1, (val >> 24) & 0x07);
self().write_data_at(2, (val >> 21) & 0x07);
self().write_data_at(3, (val >> 18) & 0x07);
self().write_data_at(4, (val >> 15) & 0x07);
self().write_data_at(5, (val >> 12) & 0x07);
self().write_data_at(6, (val >> 9) & 0x07);
self().write_data_at(7, (val >> 6) & 0x07);
self().write_data_at(8, (val >> 3) & 0x07);
self().write_data_at(9, (val >> 0) & 0x07);
self().forward(10);
break;
case 0x08: // 10xx - 6 5-bit values.
case 0x09:
case 0x0A:
case 0x0B:
self().write_data_at(0, (val >> 25) & 0x1F);
self().write_data_at(1, (val >> 20) & 0x1F);
self().write_data_at(2, (val >> 15) & 0x1F);
self().write_data_at(3, (val >> 10) & 0x1F);
self().write_data_at(4, (val >> 5) & 0x1F);
self().write_data_at(5, (val >> 0) & 0x1F);
self().forward(6);
break;
case 0x0C: // 1100 - 4 7-bit values
self().write_data_at(0, (val >> 21) & 0x7F);
self().write_data_at(1, (val >> 14) & 0x7F);
self().write_data_at(2, (val >> 7) & 0x7F);
self().write_data_at(3, (val >> 0) & 0x7F);
self().forward(4);
break;
case 0x0D: // 1101x - 3 9-bit values.
self().write_data_at(0, (val >> 18) & 0x1FF);
self().write_data_at(1, (val >> 9) & 0x1FF);
self().write_data_at(2, (val >> 0) & 0x1FF);
self().forward(3);
break;
case 0x0E: // 110x - 2 14-bit values.
self().write_data_at(0, (val >> 14) & 0x3FFF);
self().write_data_at(1, (val >> 0) & 0x3FFF);
self().forward(2);
break;
case 0x0F: // 1100 - 1 28-bit value.
self().write_data_at(0, val & 0xFFFFFFF);
self().forward(1);
break;
}
}
}
protected:
Self& self()
{
return static_cast<Self&>(*this);
}
const Self& self() const
{
return static_cast<const Self&>(*this);
}
};
class int_array_array_decompression:
public stream_decompression_base<int_array_array_decompression>
{
public:
int_array_array_decompression(const int* array,
size_t array_size,
int* res)
: array_(array), n_(array_size), pos_(0), result_(res)
{
}
void write_data_at(size_t pos, unsigned int i)
{
result_[pos] = i;
}
void forward(size_t i)
{
result_ += i;
}
bool have_comp_data() const
{
return pos_ < n_;
}
unsigned int next_comp_data()
{
return array_[pos_++];
}
protected:
const int* array_;
size_t n_;
size_t pos_;
int* result_;
};
}
void
int_array_array_decompress2(const int* array, size_t array_size, int* res,
size_t)
{
int_array_array_decompression c(array, array_size, res);
c.run();
}
} // spot

50
spot/misc/intvcmp2.hh Normal file
View file

@ -0,0 +1,50 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013, 2015 Laboratoire de Recherche et
// Developpement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <vector>
#include <stddef.h>
namespace spot
{
/// \ingroup misc_tools
/// @{
/// \brief Compress an int array of size \a n into a int array.
///
/// The destination array should be at least \a dest_size large An
/// assert will be triggered if \a dest_size is too small. On
/// return, \a dest_size will be set to the actually number of int
/// filled in \a dest
SPOT_API void
int_array_array_compress2(const int* array, size_t n,
int* dest, size_t& dest_size);
/// \brief Uncompress an int array of size \a array_size into a int
/// array of size \a size.
///
/// \a size must be the exact expected size of uncompressed array.
SPOT_API void
int_array_array_decompress2(const int* array, size_t array_size,
int* res, size_t size);
/// @}
}

703
spot/misc/intvcomp.cc Normal file
View file

@ -0,0 +1,703 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/common.hh>
#include <cstddef>
#include <cassert>
#include <spot/misc/intvcomp.hh>
namespace spot
{
// Compression scheme
// ------------------
//
// Assumptions:
// - small and positive values are more frequent than negative
// and large values.
// - 0 is the most frequent value
// - repeated values (esp. repeated 0s occur often).
//
// 00 encodes "value 0"
// 010 encodes "value 1"
// 011 encodes "a value in [2..5]" followed by 2 bits
// 100 encodes "a value in [6..22]" followed by 4 bits
// 101 encodes "repeat prev. value [1..8] times" followed by 3 bits count
// 110 encodes "repeat prev. value [9..40] times" followed by 5 bits count
// 111 encodes "an int value" followed by 32 bits
//
// If 101 or 110 occur at the start, the value to repeat is 0.
namespace
{
template <class Self>
class stream_compression_base
{
static const unsigned int max_bits = sizeof(unsigned int) * 8;
public:
stream_compression_base()
: cur_(0), bits_left_(max_bits)
{
}
void emit(unsigned int val)
{
if (val == 0)
{
self().push_bits(0x0, 2, 0x3);
}
else if (val == 1)
{
self().push_bits(0x2, 3, 0x7);
}
else if (val >= 2 && val <= 5)
{
self().push_bits(0x3, 3, 0x7);
self().push_bits(val - 2, 2, 0x3);
}
else if (val >= 6 && val <= 22)
{
self().push_bits(0x4, 3, 0x7);
self().push_bits(val - 6, 4, 0xf);
}
else
{
assert(val > 22);
self().push_bits(0x7, 3, 0x7);
self().push_bits(val, 32, -1U);
}
}
void run()
{
unsigned int last_val = 0;
while (SPOT_LIKELY(self().have_data()))
{
unsigned int val = self().next_data();
// Repeated value? Try to find more.
if (val == last_val)
{
unsigned int count = 1;
while (count < 40 && self().skip_if(val))
++count;
if ((val == 0 && count < 3) || (val == 1 && count == 1))
{
// it is more efficient to emit 0 once or twice directly
// (e.g., 00 00 vs. 011 11)
// for value 1, repetition is worthwhile for count > 1
// (e.g., 010 010 vs. 011 00)
while (count--)
emit(val);
}
else if (count < 9)
{
self().push_bits(0x5, 3, 0x7);
self().push_bits(count - 1, 3, 0x7);
}
else
{
self().push_bits(0x6, 3, 0x7);
self().push_bits(count - 9, 5, 0x1f);
}
}
else
{
emit(val);
last_val = val;
}
}
flush();
}
// This version assumes there is at least n bits free in cur_.
void
push_bits_unchecked(unsigned int bits, unsigned int n, unsigned int mask)
{
cur_ <<= n;
cur_ |= (bits & mask);
if (SPOT_LIKELY(bits_left_ -= n))
return;
self().push_data(cur_);
cur_ = 0;
bits_left_ = max_bits;
}
void
push_bits(unsigned int bits, unsigned int n, unsigned int mask)
{
if (SPOT_LIKELY(n <= bits_left_))
{
push_bits_unchecked(bits, n, mask);
return;
}
// bits_left_ < n
unsigned int right_bit_count = n - bits_left_;
unsigned int left = bits >> right_bit_count;
push_bits_unchecked(left, bits_left_, (1 << bits_left_) - 1);
push_bits_unchecked(bits, right_bit_count, (1 << right_bit_count) - 1);
}
void flush()
{
if (bits_left_ == max_bits)
return;
cur_ <<= bits_left_;
self().push_data(cur_);
}
protected:
Self& self()
{
return static_cast<Self&>(*this);
}
const Self& self() const
{
return static_cast<const Self&>(*this);
}
unsigned int cur_;
unsigned int bits_left_;
};
class int_array_vector_compression:
public stream_compression_base<int_array_vector_compression>
{
public:
int_array_vector_compression(const int* array, size_t n)
: array_(array), n_(n), pos_(0), result_(new std::vector<unsigned int>)
{
}
void push_data(unsigned int i)
{
result_->push_back(i);
}
const std::vector<unsigned int>*
result() const
{
return result_;
}
bool have_data() const
{
return pos_ < n_;
}
unsigned int next_data()
{
return static_cast<unsigned int>(array_[pos_++]);
}
bool skip_if(unsigned int val)
{
if (SPOT_UNLIKELY(!have_data()))
return false;
if (static_cast<unsigned int>(array_[pos_]) != val)
return false;
++pos_;
return true;
}
protected:
const int* array_;
size_t n_;
size_t pos_;
std::vector<unsigned int>* result_;
};
class int_vector_vector_compression:
public stream_compression_base<int_vector_vector_compression>
{
public:
int_vector_vector_compression(const std::vector<int>& input,
std::vector<unsigned int>& output)
: input_(input), pos_(input.begin()), end_(input.end()), output_(output)
{
}
void push_data(unsigned int i)
{
output_.push_back(i);
}
bool have_data() const
{
return pos_ < end_;
}
unsigned int next_data()
{
return static_cast<unsigned int>(*pos_++);
}
bool skip_if(unsigned int val)
{
if (SPOT_UNLIKELY(!have_data()))
return false;
if (static_cast<unsigned int>(*pos_) != val)
return false;
++pos_;
return true;
}
protected:
const std::vector<int>& input_;
std::vector<int>::const_iterator pos_;
std::vector<int>::const_iterator end_;
std::vector<unsigned int>& output_;
};
class int_array_array_compression:
public stream_compression_base<int_array_array_compression>
{
public:
int_array_array_compression(const int* array, size_t n,
int* dest, size_t& dest_n)
: array_(array), n_(n), pos_(0),
result_size_(dest_n), result_(dest), result_end_(dest + dest_n)
{
result_size_ = 0; // this resets dest_n.
}
void push_data(unsigned int i)
{
assert(result_ < result_end_);
++result_size_;
*result_++ = static_cast<int>(i);
}
bool have_data() const
{
return pos_ < n_;
}
unsigned int next_data()
{
return static_cast<unsigned int>(array_[pos_++]);
}
bool skip_if(unsigned int val)
{
if (SPOT_UNLIKELY(!have_data()))
return false;
if (static_cast<unsigned int>(array_[pos_]) != val)
return false;
++pos_;
return true;
}
protected:
const int* array_;
size_t n_;
size_t pos_;
size_t& result_size_;
int* result_;
int* result_end_;
};
}
void
int_vector_vector_compress(const std::vector<int>& input,
std::vector<unsigned>& output)
{
int_vector_vector_compression c(input, output);
c.run();
}
const std::vector<unsigned int>*
int_array_vector_compress(const int* array, size_t n)
{
int_array_vector_compression c(array, n);
c.run();
return c.result();
}
void
int_array_array_compress(const int* array, size_t n,
int* dest, size_t& dest_size)
{
int_array_array_compression c(array, n, dest, dest_size);
c.run();
}
//////////////////////////////////////////////////////////////////////
namespace
{
template<class Self>
class stream_decompression_base
{
static const unsigned int max_bits = sizeof(unsigned int) * 8;
public:
void refill()
{
if (SPOT_UNLIKELY(look_bits_ == 0))
{
look_bits_ = max_bits;
look_ = buffer_;
if (SPOT_LIKELY(self().have_comp_data()))
buffer_ = self().next_comp_data();
if (SPOT_LIKELY(buffer_bits_ != max_bits))
{
unsigned int fill_size = max_bits - buffer_bits_;
look_ <<= fill_size;
look_ |= buffer_ >> buffer_bits_;
}
}
else
{
unsigned int fill_size = max_bits - look_bits_;
if (fill_size > buffer_bits_)
fill_size = buffer_bits_;
look_ <<= fill_size;
buffer_bits_ -= fill_size;
look_ |= (buffer_ >> buffer_bits_) & ((1 << fill_size) - 1);
look_bits_ += fill_size;
if (buffer_bits_ == 0)
{
if (SPOT_LIKELY(self().have_comp_data()))
buffer_ = self().next_comp_data();
unsigned int left = max_bits - look_bits_;
if (left != 0)
{
look_ <<= left;
look_ |= buffer_ >> look_bits_;
buffer_bits_ = look_bits_;
look_bits_ = max_bits;
}
else
{
buffer_bits_ = max_bits;
}
}
}
}
unsigned int look_n_bits(unsigned int n)
{
if (SPOT_UNLIKELY(look_bits_ < n))
refill();
assert(n <= look_bits_);
return (look_ >> (look_bits_ - n)) & ((1 << n) - 1);
}
void skip_n_bits(unsigned int n)
{
assert (n <= look_bits_);
look_bits_ -= n;
}
unsigned int get_n_bits(unsigned int n)
{
if (SPOT_UNLIKELY(look_bits_ < n))
refill();
look_bits_ -= n;
return (look_ >> look_bits_) & ((1 << n) - 1);
}
unsigned int get_32_bits()
{
// std::cerr << "get_32" << std::endl;
if (SPOT_LIKELY(look_bits_ < 32))
refill();
unsigned int val = look_;
look_bits_ = 0;
refill();
return val;
}
void run()
{
if (SPOT_UNLIKELY(!self().have_comp_data()))
return;
look_ = self().next_comp_data();
look_bits_ = max_bits;
if (SPOT_LIKELY(self().have_comp_data()))
{
buffer_ = self().next_comp_data();
buffer_bits_ = max_bits;
}
else
{
buffer_ = 0;
buffer_bits_ = 0;
}
while (SPOT_LIKELY(!self().complete()))
{
unsigned int token = look_n_bits(3);
switch (token)
{
case 0x0: // 00[0]
case 0x1: // 00[1]
skip_n_bits(2);
self().push_data(0);
break;
case 0x2: // 010
skip_n_bits(3);
self().push_data(1);
break;
case 0x3: // 011
skip_n_bits(3);
self().push_data(2 + get_n_bits(2));
break;
case 0x4: // 100
skip_n_bits(3);
self().push_data(6 + get_n_bits(4));
break;
case 0x5: // 101
skip_n_bits(3);
self().repeat(1 + get_n_bits(3));
break;
case 0x6: // 110
skip_n_bits(3);
self().repeat(9 + get_n_bits(5));
break;
case 0x7: // 111
skip_n_bits(3);
self().push_data(get_32_bits());
break;
default:
SPOT_UNREACHABLE();
}
}
}
protected:
Self& self()
{
return static_cast<Self&>(*this);
}
const Self& self() const
{
return static_cast<const Self&>(*this);
}
unsigned int look_;
unsigned int look_bits_;
unsigned int buffer_;
unsigned int buffer_bits_;
};
class int_vector_vector_decompression:
public stream_decompression_base<int_vector_vector_decompression>
{
public:
int_vector_vector_decompression(const std::vector<unsigned int>& array,
std::vector<int>& res, size_t size)
: prev_(0), array_(array),
pos_(array.begin()), end_(array.end()),
result_(res), size_(size)
{
result_.reserve(size);
}
bool complete() const
{
return size_ == 0;
}
void push_data(int i)
{
prev_ = i;
result_.push_back(i);
--size_;
}
void repeat(unsigned int i)
{
size_ -= i;
while (i--)
result_.push_back(prev_);
}
bool have_comp_data() const
{
return pos_ != end_;
}
unsigned int next_comp_data()
{
return *pos_++;
}
protected:
int prev_;
const std::vector<unsigned int>& array_;
std::vector<unsigned int>::const_iterator pos_;
std::vector<unsigned int>::const_iterator end_;
std::vector<int>& result_;
size_t size_;
};
class int_vector_array_decompression:
public stream_decompression_base<int_vector_array_decompression>
{
public:
int_vector_array_decompression(const std::vector<unsigned int>* array,
int* res,
size_t size)
: prev_(0), array_(array), n_(array->size()), pos_(0), result_(res),
size_(size)
{
}
bool complete() const
{
return size_ == 0;
}
void push_data(int i)
{
prev_ = i;
*result_++ = i;
--size_;
}
void repeat(unsigned int i)
{
size_ -= i;
while (i--)
*result_++ = prev_;
}
bool have_comp_data() const
{
return pos_ < n_;
}
unsigned int next_comp_data()
{
return (*array_)[pos_++];
}
protected:
int prev_;
const std::vector<unsigned int>* array_;
size_t n_;
size_t pos_;
int* result_;
size_t size_;
};
class int_array_array_decompression:
public stream_decompression_base<int_array_array_decompression>
{
public:
int_array_array_decompression(const int* array,
size_t array_size,
int* res,
size_t size)
: prev_(0), array_(array), n_(array_size), pos_(0), result_(res),
size_(size)
{
}
bool complete() const
{
return size_ == 0;
}
void push_data(int i)
{
prev_ = i;
*result_++ = i;
--size_;
}
void repeat(unsigned int i)
{
size_ -= i;
while (i--)
*result_++ = prev_;
}
bool have_comp_data() const
{
return pos_ < n_;
}
unsigned int next_comp_data()
{
return array_[pos_++];
}
protected:
int prev_;
const int* array_;
size_t n_;
size_t pos_;
int* result_;
size_t size_;
};
}
void
int_vector_vector_decompress(const std::vector<unsigned int>& input,
std::vector<int>& output, size_t size)
{
int_vector_vector_decompression c(input, output, size);
c.run();
}
void
int_vector_array_decompress(const std::vector<unsigned int>* array, int* res,
size_t size)
{
int_vector_array_decompression c(array, res, size);
c.run();
}
void
int_array_array_decompress(const int* array, size_t array_size,
int* res, size_t size)
{
int_array_array_decompression c(array, array_size, res, size);
c.run();
}
}

75
spot/misc/intvcomp.hh Normal file
View file

@ -0,0 +1,75 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013, 2015 Laboratoire de Recherche et
// Developpement de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <vector>
#include <stddef.h>
namespace spot
{
/// \ingroup misc_tools
/// @{
/// Compress an int vector into a vector of unsigned int.
SPOT_API void
int_vector_vector_compress(const std::vector<int>& input,
std::vector<unsigned int>& output);
/// \brief Uncompress a vector of unsigned int into a vector of
/// size \a size.
///
/// \a size must be the exact expected size of uncompressed array.
SPOT_API void
int_vector_vector_decompress(const std::vector<unsigned int>& array,
std::vector<int>& output, size_t size);
/// Compress an int array if size \a n into a vector of unsigned int.
SPOT_API const std::vector<unsigned int>*
int_array_vector_compress(const int* array, size_t n);
/// \brief Uncompress a vector of unsigned int into an int array of
/// size \a size.
///
/// \a size must be the exact expected size of uncompressed array.
SPOT_API void
int_vector_array_decompress(const std::vector<unsigned int>* array,
int* res, size_t size);
/// \brief Compress an int array of size \a n into a int array.
///
/// The destination array should be at least \a dest_size large An
/// assert will be triggered if \a dest_size is too small. On
/// return, \a dest_size will be set to the actually number of int
/// filled in \a dest
SPOT_API void
int_array_array_compress(const int* array, size_t n,
int* dest, size_t& dest_size);
/// \brief Uncompress an int array of size \a array_size into a int
/// array of size \a size.
///
/// \a size must be the exact expected size of uncompressed array.
SPOT_API void
int_array_array_decompress(const int* array, size_t array_size,
int* res, size_t size);
/// @}
}

169
spot/misc/location.hh Normal file
View file

@ -0,0 +1,169 @@
// Note: this file was comped from A Bison parser, made by GNU Bison
// 2.7.12-4996. It is shared by all the parsers in Spot. Unfortunately,
// at the time of writing there is no Bison option to generate this
// file an update it.
/* Locations for Bison parsers in C++
Copyright (C) 2002-2007, 2009-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#pragma once
#include <spot/misc/position.hh>
namespace spot
{
/// Abstract a location.
class location
{
public:
/// Construct a location from \a b to \a e.
location (const position& b, const position& e)
: begin (b)
, end (e)
{
}
/// Construct a 0-width location in \a p.
explicit location (const position& p = position ())
: begin (p)
, end (p)
{
}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location (std::string* f,
unsigned int l = 1u,
unsigned int c = 1u)
: begin (f, l, c)
, end (f, l, c)
{
}
/// Initialization.
void initialize (std::string* f = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
{
begin.initialize (f, l, c);
end = begin;
}
/** \name Line and Column related manipulators
** \{ */
public:
/// Reset initial location to final location.
void step ()
{
begin = end;
}
/// Extend the current location to the COUNT next columns.
void columns (unsigned int count = 1)
{
end += count;
}
/// Extend the current location to the COUNT next lines.
void lines (unsigned int count = 1)
{
end.lines (count);
}
/** \} */
public:
/// Beginning of the located region.
position begin;
/// End of the located region.
position end;
};
/// Join two location objects to create a location.
inline const location operator+ (const location& begin, const location& end)
{
location res = begin;
res.end = end.end;
return res;
}
/// Add two location objects.
inline const location operator+ (const location& begin, unsigned int width)
{
location res = begin;
res.columns (width);
return res;
}
/// Add and assign a location.
inline location& operator+= (location& res, unsigned int width)
{
res.columns (width);
return res;
}
/// Compare two location objects.
inline bool
operator== (const location& loc1, const location& loc2)
{
return loc1.begin == loc2.begin && loc1.end == loc2.end;
}
/// Compare two location objects.
inline bool
operator!= (const location& loc1, const location& loc2)
{
return !(loc1 == loc2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param loc a reference to the location to redirect
**
** Avoid duplicate information.
*/
template <typename YYChar>
inline std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
{
position last = loc.end - 1;
ostr << loc.begin;
if (last.filename
&& (!loc.begin.filename
|| *loc.begin.filename != *last.filename))
ostr << '-' << last;
else if (loc.begin.line != last.line)
ostr << '-' << last.line << '.' << last.column;
else if (loc.begin.column != last.column)
ostr << '-' << last.column;
return ostr;
}
}

51
spot/misc/ltstr.hh Normal file
View file

@ -0,0 +1,51 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE)
// Copyright (C) 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <cstring>
#include <functional>
namespace spot
{
/// \ingroup misc_tools
/// \brief Strict Weak Ordering for \c char*.
///
/// This is meant to be used as a comparison functor for
/// STL \c map whose key are of type <code>const char*</code>.
///
/// For instance here is how one could declare
/// a map of <code>const state*</code>.
/// \code
/// std::map<const char*, int, spot::state_ptr_less_than> seen;
/// \endcode
struct char_ptr_less_than:
public std::binary_function<const char*, const char*, bool>
{
bool
operator()(const char* left, const char* right) const
{
return strcmp(left, right) < 0;
}
};
}

44
spot/misc/memusage.cc Normal file
View file

@ -0,0 +1,44 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013 Laboratoire de Recherche et Developpement de
// l'Epita (LRDE).
// Copyright (C) 2006 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/memusage.hh>
#include <cstdio>
namespace spot
{
int
memusage()
{
int size;
FILE* file = fopen("/proc/self/statm", "r");
if (!file)
return -1;
int res = fscanf(file, "%d", &size);
(void) fclose(file);
if (res != 1)
return -1;
return size;
}
}

34
spot/misc/memusage.hh Normal file
View file

@ -0,0 +1,34 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013 Laboratoire de Recherche et Developpement de
// l'Epita (LRDE).
// Copyright (C) 2006 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
namespace spot
{
/// \brief Total number of pages in use by the program.
///
/// \return The total number of pages in use by the program if known.
/// -1 otherwise.
SPOT_API int memusage();
}

178
spot/misc/minato.cc Normal file
View file

@ -0,0 +1,178 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris
// 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),
// Université Pierre et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/minato.hh>
#include <cassert>
namespace spot
{
minato_isop::minato_isop(bdd input)
: minato_isop(input, bdd_support(input))
{
}
minato_isop::minato_isop(bdd input, bdd vars)
: ret_(bddfalse)
{
// If INPUT has the form a&b&c&(binary function) we want to
// compute the ISOP of the only binary and prepend a&b&c latter.
//
// Calling bdd_satprefix (it returns a&b&c and modify input to
// point to function) this way is an optimization to the
// original algorithm, because in many cases we are trying to
// build ISOPs out of formulae that are already cubes.
cube_.push(bdd_satprefix(input));
todo_.emplace(input, input, vars);
}
minato_isop::minato_isop(bdd input_min, bdd input_max, bool)
: ret_(bddfalse)
{
if (input_min == input_max)
{
cube_.push(bdd_satprefix(input_min));
input_max = input_min;
}
else
{
cube_.push(bddtrue);
}
bdd common = input_min & input_max;
todo_.emplace(input_min, input_max, bdd_support(common));
}
bdd
minato_isop::next()
{
while (!todo_.empty())
{
local_vars& l = todo_.top();
switch (l.step)
{
case local_vars::FirstStep:
next_var:
{
if (l.f_min == bddfalse)
{
ret_ = bddfalse;
todo_.pop();
continue;
}
if (l.vars == bddtrue || l.f_max == bddtrue)
{
ret_ = l.f_max;
todo_.pop();
return cube_.top() & ret_;
}
assert(l.vars != bddfalse);
// Pick the first variable in VARS that is used by F_MIN
// or F_MAX. We know that VARS, F_MIN or F_MAX are not
// constants (bddtrue or bddfalse) because one of the
// two above `if' would have matched; so it's ok to call
// bdd_var().
int v = bdd_var(l.vars);
l.vars = bdd_high(l.vars);
int v_min = bdd_var(l.f_min);
int v_max = bdd_var(l.f_max);
if (v < v_min && v < v_max)
// Do not use a while() for this goto, because we want
// `continue' to be relative to the outermost while().
goto next_var;
l.step = local_vars::SecondStep;
bdd v0 = bdd_nithvar(v);
l.v1 = bdd_ithvar(v);
// All the following should be equivalent to
// f0_min = bdd_restrict(f_min, v0);
// f0_max = bdd_restrict(f_max, v0);
// f1_min = bdd_restrict(f_min, v1);
// f1_max = bdd_restrict(f_max, v1);
// but we try to avoid bdd_restrict when possible.
if (v == v_min)
{
l.f0_min = bdd_low(l.f_min);
l.f1_min = bdd_high(l.f_min);
}
else if (v_min < v)
{
l.f0_min = bdd_restrict(l.f_min, v0);
l.f1_min = bdd_restrict(l.f_min, l.v1);
}
else
{
l.f1_min = l.f0_min = l.f_min;
}
if (v == v_max)
{
l.f0_max = bdd_low(l.f_max);
l.f1_max = bdd_high(l.f_max);
}
else if (v_max < v)
{
l.f0_max = bdd_restrict(l.f_max, v0);
l.f1_max = bdd_restrict(l.f_max, l.v1);
}
else
{
l.f1_max = l.f0_max = l.f_max;
}
cube_.push(cube_.top() & v0);
todo_.emplace(l.f0_min - l.f1_max, l.f0_max, l.vars);
}
continue;
case local_vars::SecondStep:
l.step = local_vars::ThirdStep;
l.g0 = ret_;
cube_.pop();
cube_.push(cube_.top() & l.v1);
todo_.emplace(l.f1_min - l.f0_max, l.f1_max, l.vars);
continue;
case local_vars::ThirdStep:
l.step = local_vars::FourthStep;
l.g1 = ret_;
cube_.pop();
{
bdd fs_max = l.f0_max & l.f1_max;
bdd fs_min = fs_max & ((l.f0_min - l.g0) | (l.f1_min - l.g1));
todo_.emplace(fs_min, fs_max, l.vars);
}
continue;
case local_vars::FourthStep:
ret_ |= (l.g0 - l.v1) | (l.g1 & l.v1);
todo_.pop();
continue;
}
SPOT_UNREACHABLE();
}
return bddfalse;
}
}

100
spot/misc/minato.hh Normal file
View file

@ -0,0 +1,100 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <bddx.h>
#include <stack>
namespace spot
{
/// \ingroup misc_tools
/// \brief Generate an irredundant sum-of-products (ISOP) form of a
/// BDD function.
///
/// This algorithm implements a derecursived version the Minato-Morreale
/// algorithm presented in the following paper.
/** \verbatim
@InProceedings{ minato.92.sasimi,
author = {Shin-ichi Minato},
title = {Fast Generation of Irredundant Sum-of-Products Forms
from Binary Decision Diagrams},
booktitle = {Proceedings of the third Synthesis and Simulation
and Meeting International Interchange workshop
(SASIMI'92)},
pages = {64--73},
year = {1992},
address = {Kobe, Japan},
month = {April}
}
\endverbatim */
class SPOT_API minato_isop
{
public:
/// \brief Conctructor.
/// \arg input The BDD function to translate in ISOP.
minato_isop(bdd input);
/// \brief Conctructor.
/// \arg input The BDD function to translate in ISOP.
/// \arg vars The set of BDD variables to factorize in \a input.
minato_isop(bdd input, bdd vars);
/// \brief Conctructor.
///
/// This version allow some flexibility in computing the ISOP.
/// the result must be within \a input_min and \a input_max.
/// \arg input_min The minimum BDD function to translate in ISOP.
/// \arg input_max The maximum BDD function to translate in ISOP.
minato_isop(bdd input_min, bdd input_max, bool);
/// \brief Compute the next sum term of the ISOP form.
/// Return \c bddfalse when all terms have been output.
bdd next();
private:
/// Internal variables for minato_isop.
struct local_vars
{
// If you are following the paper, f_min and f_max correspond
// to the pair of BDD functions used to encode the ternary function f
// (see Section 3.4).
// Also note that f0, f0', and f0'' all share the same _max function.
// Likewise for f1, f1', and f1''.
bdd f_min, f_max;
// Because we need a non-recursive version of the algorithm,
// we had to split it in four steps (each step is separated
// from the other by a call to ISOP in the original algorithm).
enum { FirstStep, SecondStep, ThirdStep, FourthStep } step;
// The list of variables to factorize. This is an addition to
// the original algorithm.
bdd vars;
bdd v1;
bdd f0_min, f0_max;
bdd f1_min, f1_max;
bdd g0, g1;
local_vars(bdd f_min, bdd f_max, bdd vars)
: f_min(f_min), f_max(f_max), step(FirstStep), vars(vars) {}
};
std::stack<local_vars> todo_;
std::stack<bdd> cube_;
bdd ret_;
};
}

126
spot/misc/mspool.hh Normal file
View file

@ -0,0 +1,126 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013, 2015 Laboratoire de Recherche et Developpement
// de l'Epita (LRDE)
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <new>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <spot/misc/hash.hh>
namespace spot
{
/// A multiple-size memory pool implementation.
class multiple_size_pool
{
static const size_t alignment_ = 2 * sizeof(size_t) - 1;
public:
/// Create a pool.
multiple_size_pool()
: free_start_(nullptr), free_end_(nullptr), chunklist_(nullptr)
{
}
/// Free any memory allocated by this pool.
~multiple_size_pool()
{
while (chunklist_)
{
chunk_* prev = chunklist_->prev;
free(chunklist_);
chunklist_ = prev;
}
}
size_t fixsize(size_t size) const
{
if (size < sizeof(block_))
size = sizeof(block_);
return (size + alignment_ - 1) & ~(alignment_ - 1);
}
/// Allocate \a size bytes of memory.
void*
allocate(size_t size)
{
size = fixsize(size);
block_*& f = freelist_[size];
// If we have free blocks available, return the first one.
if (f)
{
block_* first = f;
f = f->next;
return first;
}
// Else, create a block out of the last chunk of allocated
// memory.
// If all the last chunk has been used, allocate one more.
if (free_start_ + size > free_end_)
{
const size_t requested = (size > 128 ? size : 128) * 8192 - 64;
chunk_* c = reinterpret_cast<chunk_*>(malloc(requested));
if (!c)
throw std::bad_alloc();
c->prev = chunklist_;
chunklist_ = c;
free_start_ = c->data_ + size;
free_end_ = c->data_ + requested;
}
void* res = free_start_;
free_start_ += size;
return res;
}
/// \brief Recycle \a size bytes of memory.
///
/// Despite the name, the memory is not really deallocated in the
/// "delete" sense: it is still owned by the pool and will be
/// reused by allocate as soon as possible. The memory is only
/// freed when the pool is destroyed.
///
/// The size argument should be the same as the one passed to
/// allocate().
void
deallocate (const void* ptr, size_t size)
{
assert(ptr);
size = fixsize(size);
block_* b = reinterpret_cast<block_*>(const_cast<void*>(ptr));
block_*& f = freelist_[size];
b->next = f;
f = b;
}
private:
struct block_ { block_* next; };
std::unordered_map<size_t, block_*> freelist_;
char* free_start_;
char* free_end_;
// chunk = several agglomerated blocks
union chunk_ { chunk_* prev; char data_[1]; }* chunklist_;
};
}

188
spot/misc/optionmap.cc Normal file
View file

@ -0,0 +1,188 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2008, 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <spot/misc/optionmap.hh>
namespace spot
{
const char*
option_map::parse_options(const char* options)
{
while (*options)
{
// Skip leading separators.
while (*options && strchr(" \t\n,;", *options))
++options;
// `!foo' is a shorthand for `foo=0'.
const char* negated = nullptr;
if (*options == '!')
{
// Skip spaces.
while (*options && strchr(" \t\n", *options))
++options;
negated = options++;
}
if (!*options)
{
if (negated)
return negated;
else
break;
}
const char* name_start = options;
// Find the end of the name.
while (*options && !strchr(", \t\n;=", *options))
++options;
std::string name(name_start, options);
// Skip spaces.
while (*options && strchr(" \t\n", *options))
++options;
if (*options != '=')
{
options_[name] = (negated ? 0 : 1);
}
else if (negated)
{
return negated;
}
else
{
++options;
// Skip spaces.
while (*options && strchr(" \t\n", *options))
++options;
if (!*options)
return name_start;
if (*options == '\'' || *options == '"')
{
auto sep = *options;
auto start = options + 1;
do
++options;
while (*options && *options != sep);
if (*options != sep)
return start - 1;
std::string val(start, options);
options_str_[name] = val;
if (*options)
++options;
}
else
{
char* val_end;
int val = strtol(options, &val_end, 10);
if (val_end == options)
return name_start;
if (*val_end == 'K')
{
val *= 1024;
++val_end;
}
else if (*val_end == 'M')
{
val *= 1024 * 1024;
++val_end;
}
else if (*val_end && !strchr(" \t\n,;", *val_end))
{
return options;
}
options = val_end;
options_[name] = val;
}
}
}
return nullptr;
}
int
option_map::get(const char* option, int def) const
{
auto it = options_.find(option);
return (it == options_.end()) ? def : it->second;
}
std::string
option_map::get_str(const char* option, std::string def) const
{
auto it = options_str_.find(option);
return (it == options_str_.end()) ? def : it->second;
}
int
option_map::operator[](const char* option) const
{
return get(option);
}
int
option_map::set(const char* option, int val, int def)
{
int old = get(option, def);
options_[option] = val;
return old;
}
std::string
option_map::set_str(const char* option, std::string val, std::string def)
{
std::string old = get_str(option, def);
options_str_[option] = val;
return old;
}
void
option_map::set(const option_map& o)
{
options_ = o.options_;
options_str_ = o.options_str_;
}
int&
option_map::operator[](const char* option)
{
return options_[option];
}
std::ostream&
operator<<(std::ostream& os, const option_map& m)
{
for (auto p: m.options_)
os << '"' << p.first << "\" = " << p.second << '\n';
for (auto p: m.options_str_)
os << '"' << p.first << "\" = \"" << p.second << "\"\n";
return os;
}
}

103
spot/misc/optionmap.hh Normal file
View file

@ -0,0 +1,103 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Developpement de
// l'Epita (LRDE)
// Copyright (C) 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <string>
#include <map>
#include <iosfwd>
namespace spot
{
/// \ingroup misc_tools
/// \brief Manage a map of options.
///
/// Each option is defined by a string and is associated to an integer value.
class SPOT_API option_map
{
public:
/// \brief Add the parsed options to the map.
///
/// \a options are separated by a space, comma, semicolon or tabulation and
/// can be optionnaly followed by an integer value (preceded by an equal
/// sign). If not specified, the default value is 1.
///
/// The following three lines are equivalent.
/** \verbatim
optA !optB optC=4194304
optA=1, optB=0, optC=4096K
optC = 4M; optA !optB
\endverbatim */
///
/// \return A non-null pointer to the option for which an expected integer
/// value cannot be parsed.
const char* parse_options(const char* options);
/// \brief Get the value of \a option.
///
/// \return The value associated to \a option if it exists,
/// \a def otherwise.
/// \see operator[]()
int get(const char* option, int def = 0) const;
/// \brief Get the value of \a option.
///
/// \return The value associated to \a option if it exists,
/// \a def otherwise.
/// \see operator[]()
std::string get_str(const char* option, std::string def = {}) const;
/// \brief Get the value of \a option.
///
/// \return The value associated to \a option if it exists, 0 otherwise.
/// \see get()
int operator[](const char* option) const;
/// \brief Set the value of \a option to \a val.
///
/// \return The previous value associated to \a option if declared,
/// or \a def otherwise.
int set(const char* option, int val, int def = 0);
/// \brief Set the value of a string \a option to \a val.
///
/// \return The previous value associated to \a option if declared,
/// or \a def otherwise.
std::string set_str(const char* option,
std::string val, std::string def = {});
/// Acquire all the settings of \a o.
void set(const option_map& o);
/// \brief Get a reference to the current value of \a option.
int& operator[](const char* option);
/// \brief Print the option_map \a m.
friend SPOT_API std::ostream&
operator<<(std::ostream& os, const option_map& m);
private:
std::map<std::string, int> options_;
std::map<std::string, std::string> options_str_;
};
}

164
spot/misc/position.hh Normal file
View file

@ -0,0 +1,164 @@
// Note: this file was comped from A Bison parser, made by GNU Bison
// 2.7.12-4996. It is shared by all the parsers in Spot. Unfortunately,
// at the time of writing there is no Bison option to generate this
// file an update it.
/* Positions for Bison parsers in C++
Copyright (C) 2002-2007, 2009-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#pragma once
#include <algorithm> // std::max
#include <iostream>
#include <string>
#ifndef YY_NULL
# if defined __cplusplus && 201103L <= __cplusplus
# define YY_NULL nullptr
# else
# define YY_NULL 0
# endif
#endif
namespace spot
{
/// Abstract a position.
class position
{
public:
/// Construct a position.
explicit position (std::string* f = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
: filename (f)
, line (l)
, column (c)
{
}
/// Initialization.
void initialize (std::string* fn = YY_NULL,
unsigned int l = 1u,
unsigned int c = 1u)
{
filename = fn;
line = l;
column = c;
}
/** \name Line and Column related manipulators
** \{ */
/// (line related) Advance to the COUNT next lines.
void lines (int count = 1)
{
column = 1u;
line += count;
}
/// (column related) Advance to the COUNT next columns.
void columns (int count = 1)
{
column = std::max (1u, column + count);
}
/** \} */
/// File name to which this position refers.
std::string* filename;
/// Current line number.
unsigned int line;
/// Current column number.
unsigned int column;
};
/// Add and assign a position.
inline position&
operator+= (position& res, const int width)
{
res.columns (width);
return res;
}
/// Add two position objects.
inline const position
operator+ (const position& begin, const int width)
{
position res = begin;
return res += width;
}
/// Add and assign a position.
inline position&
operator-= (position& res, const int width)
{
return res += -width;
}
/// Add two position objects.
inline const position
operator- (const position& begin, const int width)
{
return begin + -width;
}
/// Compare two position objects.
inline bool
operator== (const position& pos1, const position& pos2)
{
return (pos1.line == pos2.line
&& pos1.column == pos2.column
&& (pos1.filename == pos2.filename
|| (pos1.filename && pos2.filename
&& *pos1.filename == *pos2.filename)));
}
/// Compare two position objects.
inline bool
operator!= (const position& pos1, const position& pos2)
{
return !(pos1 == pos2);
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param pos a reference to the position to redirect
*/
template <typename YYChar>
inline std::basic_ostream<YYChar>&
operator<< (std::basic_ostream<YYChar>& ostr, const position& pos)
{
if (pos.filename)
ostr << *pos.filename << ':';
return ostr << pos.line << '.' << pos.column;
}
}

132
spot/misc/random.cc Normal file
View file

@ -0,0 +1,132 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2012, 2013, 2014, 2015 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/random.hh>
#include <random>
namespace spot
{
static std::mt19937 gen;
void
srand(unsigned int seed)
{
gen.seed(seed);
}
double
drand()
{
return gen() / (1.0 + gen.max());
}
int
mrand(int max)
{
return static_cast<int>(max * drand());
}
int
rrand(int min, int max)
{
return min + static_cast<int>((max - min + 1) * drand());
}
double
nrand()
{
const double r = drand();
const double lim = 1.e-20;
if (r < lim)
return -1./lim;
if (r > 1.0 - lim)
return 1./lim;
double t;
if (r < 0.5)
t = sqrt(-2.0 * log(r));
else
t = sqrt(-2.0 * log(1.0 - r));
const double p0 = 0.322232431088;
const double p1 = 1.0;
const double p2 = 0.342242088547;
const double p3 = 0.204231210245e-1;
const double p4 = 0.453642210148e-4;
const double q0 = 0.099348462606;
const double q1 = 0.588581570495;
const double q2 = 0.531103462366;
const double q3 = 0.103537752850;
const double q4 = 0.385607006340e-2;
const double p = p0 + t * (p1 + t * (p2 + t * (p3 + t * p4)));
const double q = q0 + t * (q1 + t * (q2 + t * (q3 + t * q4)));
if (r < 0.5)
return (p / q) - t;
else
return t - (p / q);
}
double
bmrand()
{
static double next;
static bool has_next = false;
if (has_next)
{
has_next = false;
return next;
}
double x;
double y;
double r;
do
{
x = 2.0 * drand() - 1.0;
y = 2.0 * drand() - 1.0;
r = x * x + y * y;
}
while (r >= 1.0 || r == 0.0);
r = sqrt(-2 * log(r) / r);
next = y * r;
has_next = true;
return x * r;
}
int
prand(double p)
{
double s = 0.0;
long x = 0;
while (s < p)
{
s -= log(1.0 - drand());
++x;
}
return x - 1;
}
}

139
spot/misc/random.hh Normal file
View file

@ -0,0 +1,139 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <cassert>
#include <cmath>
#include <vector>
namespace spot
{
/// \defgroup random Random functions
/// \ingroup misc_tools
/// \ingroup random
/// @{
/// \brief Reset the seed of the pseudo-random number generator.
///
/// \see drand, mrand, rrand
SPOT_API void srand(unsigned int seed);
/// \brief Compute a pseudo-random integer value between \a min and
/// \a max included.
///
/// \see drand, mrand, srand
SPOT_API int rrand(int min, int max);
/// \brief Compute a pseudo-random integer value between 0 and
/// \a max-1 included.
///
/// \see drand, rrand, srand
SPOT_API int mrand(int max);
/// \brief Compute a pseudo-random double value
/// between 0.0 and 1.0 (1.0 excluded).
///
/// \see mrand, rrand, srand
SPOT_API double drand();
/// \brief Compute a pseudo-random double value
/// following a standard normal distribution. (Odeh & Evans)
///
/// This uses a polynomial approximation of the inverse cumulated
/// density function from Odeh & Evans, Journal of Applied
/// Statistics, 1974, vol 23, pp 96-97.
SPOT_API double nrand();
/// \brief Compute a pseudo-random double value
/// following a standard normal distribution. (Box-Muller)
///
/// This uses the polar form of the Box-Muller transform
/// to generate random values.
SPOT_API double bmrand();
/// \brief Compute pseudo-random integer value between 0
/// and \a n included, following a binomial distribution
/// with probability \a p.
///
/// \a gen must be a random function computing a pseudo-random
/// double value following a standard normal distribution.
/// Use nrand() or bmrand().
///
/// Usually approximating a binomial distribution using a normal
/// distribution and is accurate only if <code>n*p</code> and
/// <code>n*(1-p)</code> are greater than 5.
template<double (*gen)()>
class barand
{
public:
barand(int n, double p)
: n_(n), m_(n * p), s_(sqrt(n * p * (1 - p)))
{
}
int
rand() const
{
for (;;)
{
int x = round(gen() * s_ + m_);
if (x < 0)
continue;
if (x <= n_)
return x;
}
SPOT_UNREACHABLE();
return 0;
}
protected:
const int n_;
const double m_;
const double s_;
};
/// \brief Return a pseudo-random positive integer value
/// following a Poisson distribution with parameter \a p.
///
/// \pre <code>p > 0</code>
SPOT_API int prand(double p);
/// \brief Shuffle the container using mrand function above.
/// This allows to get rid off shuffle or random_shuffle that use
/// uniform_distribution and RandomIterator that are not portables.
template<class iterator_type>
SPOT_API void mrandom_shuffle(iterator_type&& first, iterator_type&& last)
{
auto d = std::distance(first, last);
if (d > 1)
{
for (--last; first < last; ++first, --d)
{
auto i = mrand(d);
std::swap(*first, *(first + i));
}
}
}
/// @}
}

168
spot/misc/satsolver.cc Normal file
View file

@ -0,0 +1,168 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2014, 2015 Laboratoire de Recherche et Développement
// de l'Epita.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/formater.hh>
#include <cstdlib>
#include <sstream>
#include <stdexcept>
#include <spot/misc/satsolver.hh>
#include <fstream>
#include <limits>
#include <sys/wait.h>
namespace spot
{
namespace
{
struct satsolver_command: formater
{
const char* satsolver;
satsolver_command()
{
satsolver = getenv("SPOT_SATSOLVER");
if (!satsolver)
{
satsolver = "glucose -verb=0 -model %I >%O";
return;
}
prime(satsolver);
if (!has('I'))
throw std::runtime_error("SPOT_SATSOLVER should contain %I to "
"indicate how to use the input filename.");
if (!has('O'))
throw std::runtime_error("SPOT_SATSOLVER should contain %O to "
"indicate how to use the output filename.");
}
int
run(printable* in, printable* out)
{
declare('I', in);
declare('O', out);
std::ostringstream s;
format(s, satsolver);
int res = system(s.str().c_str());
if (res < 0 || (WIFEXITED(res) && WEXITSTATUS(res) == 127))
{
s << ": failed to execute";
throw std::runtime_error(s.str());
}
// For POSIX shells, "The exit status of a command that
// terminated because it received a signal shall be reported
// as greater than 128."
if (WIFEXITED(res) && WEXITSTATUS(res) >= 128)
{
s << ": terminated by signal";
throw std::runtime_error(s.str());
}
if (WIFSIGNALED(res))
{
s << ": terminated by signal " << WTERMSIG(res);
throw std::runtime_error(s.str());
}
return res;
}
};
}
satsolver::solution
satsolver_get_solution(const char* filename)
{
satsolver::solution sol;
std::istream* in;
if (filename[0] == '-' && filename[1] == 0)
in = &std::cin;
else
in = new std::fstream(filename, std::ios_base::in);
int c;
while ((c = in->get()) != EOF)
{
// If a line does not start with 'v ', ignore it.
if (c != 'v' || in->get() != ' ')
{
in->ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
// Otherwise, read integers one by one.
int i;
while (*in >> i)
{
if (i == 0)
goto done;
sol.push_back(i);
}
if (!in->eof())
// If we haven't reached end-of-file, then we just attempted
// to extract something that wasn't an integer. Clear the
// fail bit so that will loop over.
in->clear();
}
done:
if (in != &std::cin)
delete in;
return sol;
}
satsolver::satsolver()
: cnf_tmp_(nullptr), cnf_stream_(nullptr)
{
start();
}
void satsolver::start()
{
cnf_tmp_ = create_tmpfile("sat-", ".cnf");
cnf_stream_ = new std::fstream(cnf_tmp_->name(),
std::ios_base::trunc | std::ios_base::out);
cnf_stream_->exceptions(std::ifstream::failbit | std::ifstream::badbit);
}
satsolver::~satsolver()
{
delete cnf_tmp_;
delete cnf_stream_;
}
std::ostream& satsolver::operator()()
{
return *cnf_stream_;
}
satsolver::solution_pair
satsolver::get_solution()
{
delete cnf_stream_; // Close the file.
cnf_stream_ = nullptr;
temporary_file* output = create_tmpfile("sat-", ".out");
solution_pair p;
// Make this static, so the SPOT_SATSOLVER lookup is done only on
// the first call to run_sat().
static satsolver_command cmd;
p.first = cmd.run(cnf_tmp_, output);
p.second = satsolver_get_solution(output->name());
delete output;
return p;
}
}

100
spot/misc/satsolver.hh Normal file
View file

@ -0,0 +1,100 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013 Laboratoire de Recherche et Développement
// de l'Epita.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <spot/misc/tmpfile.hh>
#include <vector>
#include <stdexcept>
#include <iosfwd>
namespace spot
{
class printable;
class clause_counter
{
private:
int count_;
public:
clause_counter()
: count_(0)
{
}
void check() const
{
if (count_ < 0)
throw std::runtime_error("too many SAT clauses (more than INT_MAX)");
}
clause_counter& operator++()
{
++count_;
check();
return *this;
}
clause_counter& operator+=(int n)
{
count_ += n;
check();
return *this;
}
int nb_clauses() const
{
return count_;
}
};
/// \brief Interface with a SAT solver.
///
/// Call start() to create some temporary file, then send DIMACs
/// text to the stream returned by operator(), and finally call
/// get_solution().
///
/// The satsolver called can be configured via the
/// <code>SPOT_SATSOLVER</code> environment variable. It
/// defaults to
/// "satsolver -verb=0 %I >%O"
/// where %I and %O are replaced by input and output files.
class SPOT_API satsolver
{
public:
satsolver();
~satsolver();
void start();
std::ostream& operator()();
typedef std::vector<int> solution;
typedef std::pair<int, solution> solution_pair;
solution_pair get_solution();
private:
temporary_file* cnf_tmp_;
std::ostream* cnf_stream_;
};
/// \brief Extract the solution of a SAT solver output.
SPOT_API satsolver::solution
satsolver_get_solution(const char* filename);
}

98
spot/misc/timer.cc Normal file
View file

@ -0,0 +1,98 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2013, 2014 Laboratoire de Recherche et
// Développement de l'Epita (LRDE).
// Copyright (C) 2004, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/timer.hh>
#include <iostream>
#include <iomanip>
namespace spot
{
std::ostream&
timer_map::print(std::ostream& os) const
{
std::ios::fmtflags old = std::cout.flags();
std::cout << std::right << std::fixed << std::setprecision(1);
time_info total;
for (tm_type::const_iterator i = tm.begin(); i != tm.end(); ++i)
{
total.utime += i->second.first.utime();
total.stime += i->second.first.stime();
}
clock_t grand_total = total.utime + total.stime;
os << std::setw(23) << ""
<< "| user time | sys. time | total |"
<< std::endl
<< std::setw(23) << "name "
<< "| ticks % | ticks % | ticks % | n"
<< std::endl
<< std::setw(79) << std::setfill('-') << "" << std::setfill(' ')
<< std::endl;
for (tm_type::const_iterator i = tm.begin(); i != tm.end(); ++i)
{
// truncate long keys
std::string name = i->first;
if (name.size() > 22)
name.erase(22);
const spot::timer& t = i->second.first;
const char* sep = t.is_running() ? "+|" : " |";
os << std::setw(22) << name << sep
<< std::setw(6) << t.utime() << ' '
<< std::setw(8) << (total.utime ?
100.0 * t.utime() / total.utime : 0.)
<< sep
<< std::setw(6) << t.stime() << ' '
<< std::setw(8) << (total.stime ?
100.0 * t.stime() / total.stime : 0.)
<< sep
<< std::setw(6) << t.utime() + t.stime() << ' '
<< std::setw(8) << (grand_total ?
(100.0 * (t.utime() + t.stime()) /
grand_total) : 0.)
<< sep
<< std::setw(4) << i->second.second
<< std::endl;
}
os << std::setw(79) << std::setfill('-') << "" << std::setfill(' ')
<< std::endl
<< std::setw(22) << "TOTAL" << " |"
<< std::setw(6) << total.utime << ' '
<< std::setw(8) << 100.
<< " |"
<< std::setw(6) << total.stime << ' '
<< std::setw(8) << 100.
<< " |"
<< std::setw(6) << grand_total << ' '
<< std::setw(8) << 100.
<< " |"
<< std::endl;
std::cout << std::setiosflags(old);
return os;
}
}

248
spot/misc/timer.hh Normal file
View file

@ -0,0 +1,248 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2009, 2011, 2012, 2013, 2014, 2015 Laboratoire de
// Recherche et Développement de l'Epita (LRDE).
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <spot/misc/_config.h>
#include <cassert>
#include <iosfwd>
#include <string>
#include <map>
#include <chrono>
#if SPOT_HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include <ctime>
namespace spot
{
/// \ingroup misc_tools
/// @{
/// \brief A simple stopwatch
struct stopwatch
{
protected:
typedef std::chrono::high_resolution_clock clock;
clock::time_point start_;
public:
/// Marks the start if the measurement
void start()
{
start_ = clock::now();
}
/// \brief Returns the elapsed duration in seconds.
///
/// May be called multiple times, and will always return the
/// duration since the last call to start().
double stop()
{
auto t = clock::now();
typedef std::chrono::duration<double> seconds;
return std::chrono::duration_cast<seconds>(t - start_).count();
}
};
/// A structure to record elapsed time in clock ticks.
struct time_info
{
time_info()
: utime(0), stime(0)
{
}
clock_t utime;
clock_t stime;
};
/// A timekeeper that accumulate interval of time.
class timer
{
public:
timer()
: running(false)
{
}
/// Start a time interval.
void
start()
{
assert(!running);
running = true;
#ifdef SPOT_HAVE_TIMES
struct tms tmp;
times(&tmp);
start_.utime = tmp.tms_utime + tmp.tms_cutime;
start_.stime = tmp.tms_stime + tmp.tms_cstime;
#else
start_.utime = clock();
#endif
}
/// Stop a time interval and update the sum of all intervals.
void
stop()
{
#ifdef SPOT_HAVE_TIMES
struct tms tmp;
times(&tmp);
total_.utime += tmp.tms_utime + tmp.tms_cutime - start_.utime;
total_.stime += tmp.tms_stime + tmp.tms_cstime - start_.stime;
#else
total_.utime += clock() - start_.utime;
#endif
assert(running);
running = false;
}
/// \brief Return the user time of all accumulated interval.
///
/// Any time interval that has been start()ed but not stop()ed
/// will not be accounted for.
clock_t
utime() const
{
return total_.utime;
}
/// \brief Return the system time of all accumulated interval.
///
/// Any time interval that has been start()ed but not stop()ed
/// will not be accounted for.
clock_t
stime() const
{
return total_.stime;
}
/// \brief Whether the timer is running.
bool
is_running() const
{
return running;
}
protected:
time_info start_;
time_info total_;
bool running;
};
/// \brief A map of timer, where each timer has a name.
///
/// Timer_map also keeps track of the number of measures each timer
/// has performed.
class timer_map
{
public:
/// \brief Start a timer with name \a name.
///
/// The timer is created if it did not exist already.
/// Once started, a timer should be either stop()ed or
/// cancel()ed.
void
start(const std::string& name)
{
item_type& it = tm[name];
it.first.start();
++it.second;
}
/// \brief Stop timer \a name.
///
/// The timer must have been previously started with start().
void
stop(const std::string& name)
{
tm[name].first.stop();
}
/// \brief Cancel timer \a name.
///
/// The timer must have been previously started with start().
///
/// This cancel only the current measure. (Previous measures
/// recorded by the timer are preserved.) When a timer that has
/// not done any measure is canceled, it is removed from the map.
void
cancel(const std::string& name)
{
tm_type::iterator i = tm.find(name);
assert(i != tm.end());
assert(0 < i->second.second);
if (0 == --i->second.second)
tm.erase(i);
}
/// Return the timer \a name.
const spot::timer&
timer(const std::string& name) const
{
tm_type::const_iterator i = tm.find(name);
assert(i != tm.end());
return i->second.first;
}
/// Return the timer \a name.
spot::timer&
timer(const std::string& name)
{
return tm[name].first;
}
/// \brief Whether there is no timer in the map.
///
/// If empty() return true, then either no timer where ever
/// started, or all started timers were canceled without
/// completing any measure.
bool
empty() const
{
return tm.empty();
}
/// Format information about all timers in a table.
SPOT_API std::ostream&
print(std::ostream& os) const;
/// \brief Remove information about all timers.
void
reset_all()
{
tm.clear();
}
protected:
typedef std::pair<spot::timer, int> item_type;
typedef std::map<std::string, item_type> tm_type;
tm_type tm;
};
/// @}
}

148
spot/misc/tmpfile.cc Normal file
View file

@ -0,0 +1,148 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/tmpfile.hh>
#include <errno.h>
#include <cstdlib>
#include <unistd.h>
#include <string.h>
namespace spot
{
namespace
{
std::list<temporary_file*> to_clean;
static const char*
get_tmpdir()
{
const char* res = secure_getenv("SPOT_TMPDIR");
if (res)
return res;
return secure_getenv("TMPDIR");
}
static int
create_temporary_file(const char* prefix,
const char* suffix,
char** name)
throw(std::bad_alloc, std::runtime_error)
{
static const char* tmpdir = get_tmpdir();
static int tmpdirlen = tmpdir ? strlen(tmpdir) : 0;
size_t len = strlen(prefix);
size_t slen = 0;
if (suffix)
len += slen = strlen(suffix);
char* x = *name = static_cast<char*>(malloc(tmpdirlen + 1 + len + 6 + 1));
if (!x)
throw std::bad_alloc();
if (tmpdir)
{
x = stpcpy(x, tmpdir);
if (x[-1] != '/')
*x++ = '/';
}
x = stpcpy(x, prefix);
x = stpcpy(x, "XXXXXX");
int fd;
if (suffix)
{
stpcpy(x, suffix);
fd = mkstemps(*name, slen);
}
else
{
fd = mkstemp(*name);
}
if (fd < 0)
throw std::runtime_error(std::string("failed to create ") + *name);
return fd;
}
}
temporary_file::temporary_file(char* name, cleanpos_t cp)
: name_(name), cleanpos_(cp)
{
}
temporary_file::~temporary_file()
{
static bool must_unlink = !secure_getenv("SPOT_TMPKEEP");
if (must_unlink)
unlink(name_);
free(name_);
to_clean.erase(cleanpos_);
}
open_temporary_file::open_temporary_file(char* name, cleanpos_t cp, int fd)
: temporary_file(name, cp), fd_(fd)
{
}
open_temporary_file::~open_temporary_file()
{
close();
}
void
open_temporary_file::close()
{
if (fd_ < 0)
return;
if (::close(fd_))
throw std::runtime_error(std::string("failed to close ") + name_);
fd_ = -1;
}
temporary_file*
create_tmpfile(const char* prefix, const char* suffix)
throw(std::bad_alloc, std::runtime_error)
{
char* name;
int fd = create_temporary_file(prefix, suffix, &name);
if (close(fd))
throw std::runtime_error(std::string("failed to close ") + name);
auto cp = to_clean.insert(to_clean.end(), nullptr);
*cp = new temporary_file(name, cp);
return *cp;
}
open_temporary_file*
create_open_tmpfile(const char* prefix, const char* suffix)
throw(std::bad_alloc, std::runtime_error)
{
char* name;
int fd = create_temporary_file(prefix, suffix, &name);
auto cp = to_clean.insert(to_clean.end(), nullptr);
open_temporary_file* otf = new open_temporary_file(name, cp, fd);
*cp = otf;
return otf;
}
void
cleanup_tmpfiles()
{
while (!to_clean.empty())
delete to_clean.front();
}
}

139
spot/misc/tmpfile.hh Normal file
View file

@ -0,0 +1,139 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013, 2015 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
#include <new>
#include <stdexcept>
#include <iostream>
#include <list>
#include <spot/misc/formater.hh>
namespace spot
{
/// \ingroup misc_tools
/// @{
/// \brief Temporary file name
///
/// This class serves a dual purpose.
///
/// 1. It carries the name of a temporary file, created with
/// create_tmpfile().
/// 2. It represents the life of the associated file. The file is
/// erased as soon as the temporary_file instance is destroyed.
///
/// Note that there are two ways to destroy temporary_file
/// instances. Either directly with delete, or indirectly by
/// calling cleanup_tmpfiles().
/// You should never delete an instance that has been created
/// before the last call to cleanup_tmpfiles(), because that
/// instance has already been deleted.
class SPOT_API temporary_file: public printable
{
public:
typedef std::list<temporary_file*>::iterator cleanpos_t;
SPOT_LOCAL temporary_file(char* name, cleanpos_t cp);
virtual ~temporary_file() override;
const char* name() const
{
return name_;
}
friend std::ostream& operator<<(std::ostream& os, const temporary_file* f)
{
os << f->name();
return os;
}
virtual void
print(std::ostream& os, const char*) const final override
{
os << this;
}
protected:
char* name_;
cleanpos_t cleanpos_;
};
/// \brief Open temporary file
///
/// This is a specialization of temporary_file that also holds an
/// open file descriptor, as created by create_open_tmpfile().
///
/// Use the open_temporary_file::close() method if you want to close
/// that descriptor; do no call the POSIX close() function directly.
class SPOT_API open_temporary_file final: public temporary_file
{
public:
SPOT_LOCAL open_temporary_file(char* name, cleanpos_t cp, int fd);
virtual ~open_temporary_file() override;
void close();
int fd() const
{
return fd_;
}
protected:
int fd_;
};
/// \brief Create a temporary file.
///
/// The file name will start with \a prefix, be followed by 6
/// randomish characters and will end in \a suffix. Usually suffix
/// is used to set an extension (you should include the dot).
///
/// The temporary file is created and left empty. If you need
/// to fill it, consider using create_open_tmpfile() instead.
SPOT_API temporary_file*
create_tmpfile(const char* prefix, const char* suffix = nullptr)
throw(std::bad_alloc, std::runtime_error);
/// \brief Create a temporary file and leave it open for writing.
///
/// Same as create_tmpfile, be leave the file open for writing. The
/// open_temporary_file::fd() method returns the file descriptor.
SPOT_API open_temporary_file*
create_open_tmpfile(const char* prefix, const char* suffix = nullptr)
throw(std::bad_alloc, std::runtime_error);
/// \brief Delete all temporary files.
///
/// Delete all temporary files that have been created but haven't
/// been deleted so far. The verb "delete" should be understood as
/// both the C++ delete operator (all temporary_file and
/// open_temporary_file instance are destroyed) and as the file
/// system operation (the actual files are removed).
///
/// Even in programs where temporary_file instance are consciously
/// destroyed when they are not needed, cleanup_tmpfiles() could
/// still be useful in signal handlers, for instance to clean all
/// temporary files upon SIGINT.
SPOT_API void
cleanup_tmpfiles();
/// @}
}

36
spot/misc/version.cc Normal file
View file

@ -0,0 +1,36 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2011, 2013 Laboratoire de Recherche et Développement de
// l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config.h"
#include <spot/misc/_config.h>
#include <spot/misc/version.hh>
namespace spot
{
static const char version_[] = SPOT_VERSION;
const char*
version()
{
return version_;
}
}

32
spot/misc/version.hh Normal file
View file

@ -0,0 +1,32 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2013 Laboratoire de Recherche et Développement
// de l'Epita (LRDE).
// Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <spot/misc/common.hh>
namespace spot
{
/// \ingroup misc_tools
/// \brief Return Spot's version.
SPOT_API const char* version();
}