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:
parent
1fddfe60ec
commit
f120dd3206
529 changed files with 1308 additions and 1262 deletions
7
spot/misc/.gitignore
vendored
Normal file
7
spot/misc/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
.deps
|
||||
.libs
|
||||
*.lo
|
||||
*.la
|
||||
_config.h
|
||||
73
spot/misc/Makefile.am
Normal file
73
spot/misc/Makefile.am
Normal 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
65
spot/misc/bareword.cc
Normal 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
53
spot/misc/bareword.hh
Normal 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
53
spot/misc/bddlt.hh
Normal 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
192
spot/misc/bitvect.cc
Normal 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
534
spot/misc/bitvect.hh
Normal 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
35
spot/misc/casts.hh
Normal 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
118
spot/misc/common.hh
Normal 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
162
spot/misc/escape.cc
Normal 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 << "&";
|
||||
break;
|
||||
case '"':
|
||||
os << """;
|
||||
break;
|
||||
case '<':
|
||||
os << "<";
|
||||
break;
|
||||
case '>':
|
||||
os << ">";
|
||||
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
73
spot/misc/escape.hh
Normal 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>> < " &</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
112
spot/misc/fixpool.hh
Normal 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
62
spot/misc/formater.cc
Normal 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
200
spot/misc/formater.hh
Normal 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
91
spot/misc/hash.hh
Normal 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
66
spot/misc/hashfunc.hh
Normal 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
551
spot/misc/intvcmp2.cc
Normal 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
50
spot/misc/intvcmp2.hh
Normal 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
703
spot/misc/intvcomp.cc
Normal 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
75
spot/misc/intvcomp.hh
Normal 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
169
spot/misc/location.hh
Normal 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
51
spot/misc/ltstr.hh
Normal 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
44
spot/misc/memusage.cc
Normal 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
34
spot/misc/memusage.hh
Normal 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
178
spot/misc/minato.cc
Normal 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
100
spot/misc/minato.hh
Normal 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
126
spot/misc/mspool.hh
Normal 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
188
spot/misc/optionmap.cc
Normal 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
103
spot/misc/optionmap.hh
Normal 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
164
spot/misc/position.hh
Normal 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
132
spot/misc/random.cc
Normal 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
139
spot/misc/random.hh
Normal 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
168
spot/misc/satsolver.cc
Normal 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
100
spot/misc/satsolver.hh
Normal 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
98
spot/misc/timer.cc
Normal 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
248
spot/misc/timer.hh
Normal 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
148
spot/misc/tmpfile.cc
Normal 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
139
spot/misc/tmpfile.hh
Normal 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
36
spot/misc/version.cc
Normal 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
32
spot/misc/version.hh
Normal 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();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue