mirror of https://github.com/KLayout/klayout.git
Merge 4eaae15ce0 into 564111af77
This commit is contained in:
commit
07fcd4f652
|
|
@ -8,6 +8,7 @@ DEFINES += MAKE_DB_LIBRARY
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
dbArray.cc \
|
dbArray.cc \
|
||||||
|
dbBinnedAreaCollector.cc \
|
||||||
dbBox.cc \
|
dbBox.cc \
|
||||||
dbBoxConvert.cc \
|
dbBoxConvert.cc \
|
||||||
dbBoxScanner.cc \
|
dbBoxScanner.cc \
|
||||||
|
|
@ -245,6 +246,7 @@ SOURCES = \
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
dbArray.h \
|
dbArray.h \
|
||||||
|
dbBinnedAreaCollector.h \
|
||||||
dbBoxConvert.h \
|
dbBoxConvert.h \
|
||||||
dbBox.h \
|
dbBox.h \
|
||||||
dbBoxScanner.h \
|
dbBoxScanner.h \
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dbBinnedAreaCollector.h"
|
||||||
|
#include "dbTypes.h"
|
||||||
|
#include "dbRegion.h"
|
||||||
|
|
||||||
|
#include "gsiDecl.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace db
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class AreaReceiver
|
||||||
|
: public db::binned_area_receiver<unsigned int>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||||
|
|
||||||
|
AreaReceiver (unsigned int count)
|
||||||
|
{
|
||||||
|
m_areas.resize (count, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void add_area (area_type area, const unsigned int &index)
|
||||||
|
{
|
||||||
|
m_areas [index] += area;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<area_type> &get () const
|
||||||
|
{
|
||||||
|
return m_areas;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<area_type> m_areas;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this does not belong here. It is an experimental feature
|
||||||
|
|
||||||
|
static std::vector<AreaReceiver::area_type>
|
||||||
|
binned_area (const std::vector<const db::Region *> &inputs, const std::vector<std::string> &vectors)
|
||||||
|
{
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
|
unsigned int index = 0;
|
||||||
|
for (auto r = inputs.begin (); r != inputs.end (); ++r, ++index) {
|
||||||
|
for (auto p = (*r)->begin (); ! p.at_end (); ++p) {
|
||||||
|
ep.insert (*p, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tl::bit_set_map<unsigned int> bsm;
|
||||||
|
index = 0;
|
||||||
|
for (auto i = vectors.begin (); i != vectors.end (); ++i, ++index) {
|
||||||
|
bsm.insert (tl::BitSetMask (*i), index);
|
||||||
|
}
|
||||||
|
bsm.sort ();
|
||||||
|
|
||||||
|
AreaReceiver rec (index);
|
||||||
|
db::binned_area_collector<unsigned int> coll (bsm, rec);
|
||||||
|
ep.process (coll, coll);
|
||||||
|
|
||||||
|
return rec.get ();
|
||||||
|
}
|
||||||
|
|
||||||
|
gsi::ClassExt<db::Region> extend_region_by_binned_area (
|
||||||
|
gsi::method ("binned_area", &binned_area, gsi::arg ("inputs"), gsi::arg ("masks"),
|
||||||
|
"@brief Computes the areas of a binned decomposition of the overall region.\n"
|
||||||
|
"In this function, the overall region is decomposed into subregions with different overlap situations. "
|
||||||
|
"Each overlap case is assigned a bin using a bit mask from the 'masks' argument. "
|
||||||
|
"Each bit corresponds to one input from 'inputs' - bit 0 is the first one etc.\n"
|
||||||
|
"The masks are strings of characters 0, 1 or 'X', representing 'inside', 'outside' and "
|
||||||
|
"'any' for the respective input. The first character represents the first input, the second the second input etc.\n"
|
||||||
|
"Missing characters are treated as 'any', so the empty string matches every situation.\n"
|
||||||
|
"\n"
|
||||||
|
"The result is a vector of accumulated areas for each bin identified by one mask. "
|
||||||
|
"Bins may overlay if multiple masks match, so the total sum of areas is not necessarily "
|
||||||
|
"identical to the total area. A bin with an empty string mask will deliver the total area.\n"
|
||||||
|
"\n"
|
||||||
|
"Merge semantics always applies - i.e. all shapes inside the regions are conceptually "
|
||||||
|
"merged in 'positive wrap count' mode before computing the area. Hence overlapping shapes "
|
||||||
|
"per input region just count once.\n"
|
||||||
|
"\n"
|
||||||
|
"Example:\n"
|
||||||
|
"\n"
|
||||||
|
"@code\n"
|
||||||
|
"r1 = RBA::Region::new\n"
|
||||||
|
"r1.insert(RBA::Box::new(0, 0, 1000, 2000))\n"
|
||||||
|
"\n"
|
||||||
|
"r2 = RBA::Region::new\n"
|
||||||
|
"r2.insert(RBA::Box::new(500, 1000, 1500, 3000))\n"
|
||||||
|
"\n"
|
||||||
|
"areas = RBA::Region::binned_area([ r1, r2 ], [ \"10\", \"01\", \"\" ])\n"
|
||||||
|
"r1_not_r2, r2_not_r1, all = areas\n"
|
||||||
|
"@/code\n"
|
||||||
|
"\n"
|
||||||
|
"This feature is highly experimental."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,237 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HDR_dbBinnedAreaCollector
|
||||||
|
#define HDR_dbBinnedAreaCollector
|
||||||
|
|
||||||
|
#include "dbCommon.h"
|
||||||
|
|
||||||
|
#include "dbEdgeProcessor.h"
|
||||||
|
#include "tlBitSetMap.h"
|
||||||
|
|
||||||
|
namespace db {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The receiver for the binned partial areas
|
||||||
|
*
|
||||||
|
* See description of binned_area_collector for details.
|
||||||
|
*/
|
||||||
|
template <class Value>
|
||||||
|
class DB_PUBLIC_TEMPLATE binned_area_receiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
binned_area_receiver<Value> () { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
virtual ~binned_area_receiver () { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This method gets called when the scanline process starts
|
||||||
|
*/
|
||||||
|
virtual void start () { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This method gets called when the scanline process finishes
|
||||||
|
*/
|
||||||
|
virtual void finish () { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds some partial area with the given value
|
||||||
|
*/
|
||||||
|
virtual void add_area (area_type /*area*/, const Value & /*value*/) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A helper class providing an inserter that is the connection between the receiver and the provider
|
||||||
|
*/
|
||||||
|
template <class Value>
|
||||||
|
class DB_PUBLIC_TEMPLATE binned_area_inserter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||||
|
|
||||||
|
binned_area_inserter<Value> (area_type area, binned_area_receiver<Value> *receiver)
|
||||||
|
: m_area (area), mp_receiver (receiver)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// methods necessary, so this object can act as an inserter
|
||||||
|
binned_area_inserter<Value> &operator* () { return *this; }
|
||||||
|
binned_area_inserter<Value> &operator++ (int) { return *this; }
|
||||||
|
|
||||||
|
binned_area_inserter<Value> &operator= (const Value &value)
|
||||||
|
{
|
||||||
|
mp_receiver->add_area (m_area, value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
area_type m_area;
|
||||||
|
binned_area_receiver<Value> *mp_receiver;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the operation and edge receiver part of the binned area collector
|
||||||
|
*
|
||||||
|
* Use this object both as the edge operator and as an edge collector.
|
||||||
|
* After running the edge processor, use "area" to obtain the area.
|
||||||
|
*
|
||||||
|
* This method collects "binned areas". That is, each field of the area divided by
|
||||||
|
* the edges carries a bit set which is made from the combinations of overlapping
|
||||||
|
* layers. The layers are given by the property number where the number is the
|
||||||
|
* bit set in the bit field. Hence, every field is associated with a bit set.
|
||||||
|
*
|
||||||
|
* The Area collector will now report the field's areas for accumulation together with
|
||||||
|
* a field value that is obtained from the bit set map. As the bit set map
|
||||||
|
* may deliver multiple fields, multiple such values can be present for each field.
|
||||||
|
* The areas are reported through the binned_area_receiver object. This object
|
||||||
|
* is supposed to add up the areas in an application specific fashion.
|
||||||
|
*/
|
||||||
|
template <class Value>
|
||||||
|
class DB_PUBLIC_TEMPLATE binned_area_collector
|
||||||
|
: public EdgeEvaluatorBase,
|
||||||
|
public EdgeSink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
binned_area_collector<Value> (const tl::bit_set_map<Value> &bsm, binned_area_receiver<Value> &receiver)
|
||||||
|
: mp_bsm (&bsm), mp_receiver (&receiver), m_state_one_bits (0), m_prev_one_bits (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementation of EdgeEvaluatorBase
|
||||||
|
virtual void reset ()
|
||||||
|
{
|
||||||
|
m_prev = tl::BitSet ();
|
||||||
|
m_state = tl::BitSet ();
|
||||||
|
m_state_one_bits = 0;
|
||||||
|
m_prev_one_bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void begin_group ()
|
||||||
|
{
|
||||||
|
m_prev = m_state;
|
||||||
|
m_prev_one_bits = m_state_one_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int edge (bool north, bool enter, property_type p)
|
||||||
|
{
|
||||||
|
if (north) {
|
||||||
|
|
||||||
|
while (m_counts.size () <= p) {
|
||||||
|
m_counts.push_back (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int &count = m_counts [p];
|
||||||
|
if (enter) {
|
||||||
|
if (count == 0) {
|
||||||
|
m_state.set (p);
|
||||||
|
++m_state_one_bits;
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
} else {
|
||||||
|
--count;
|
||||||
|
if (count == 0) {
|
||||||
|
m_state.reset (p);
|
||||||
|
--m_state_one_bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this will call "put" when the group is finished
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool is_reset () const
|
||||||
|
{
|
||||||
|
return m_state_one_bits == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool prefer_touch () const
|
||||||
|
{
|
||||||
|
// leave events come before enter events
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool selects_edges () const
|
||||||
|
{
|
||||||
|
// select_edge is not needed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementation of EdgeSink
|
||||||
|
|
||||||
|
virtual void start ()
|
||||||
|
{
|
||||||
|
mp_receiver->start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush ()
|
||||||
|
{
|
||||||
|
mp_receiver->finish ();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void put (const db::Edge &, int)
|
||||||
|
{
|
||||||
|
// not used.
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void put (const db::Edge &edge)
|
||||||
|
{
|
||||||
|
area_type partial_area = area_type (edge.p1 ().x () + edge.p2 ().x ()) * area_type (edge.dy ()) * 0.5;
|
||||||
|
if (m_prev_one_bits > 0) {
|
||||||
|
mp_bsm->lookup (m_prev, binned_area_inserter<Value> (partial_area, mp_receiver));
|
||||||
|
}
|
||||||
|
if (m_state_one_bits > 0) {
|
||||||
|
mp_bsm->lookup (m_state, binned_area_inserter<Value> (-partial_area, mp_receiver));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
area_type m_area_sum;
|
||||||
|
const tl::bit_set_map<Value> *mp_bsm;
|
||||||
|
binned_area_receiver<Value> *mp_receiver;
|
||||||
|
tl::BitSet m_prev, m_state;
|
||||||
|
std::vector<int> m_counts;
|
||||||
|
unsigned int m_state_one_bits, m_prev_one_bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -1670,6 +1670,7 @@ public:
|
||||||
void next_coincident ()
|
void next_coincident ()
|
||||||
{
|
{
|
||||||
m_pn = m_ps = 0;
|
m_pn = m_ps = 0;
|
||||||
|
mp_op->begin_group ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void end_coincident ()
|
void end_coincident ()
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,7 @@ public:
|
||||||
|
|
||||||
virtual void reset () { }
|
virtual void reset () { }
|
||||||
virtual void reserve (size_t /*n*/) { }
|
virtual void reserve (size_t /*n*/) { }
|
||||||
|
virtual void begin_group () { }
|
||||||
virtual int edge (bool /*north*/, bool /*enter*/, property_type /*p*/) { return 0; }
|
virtual int edge (bool /*north*/, bool /*enter*/, property_type /*p*/) { return 0; }
|
||||||
virtual int select_edge (bool /*horizontal*/, property_type /*p*/) { return 0; }
|
virtual int select_edge (bool /*horizontal*/, property_type /*p*/) { return 0; }
|
||||||
virtual int compare_ns () const { return 0; }
|
virtual int compare_ns () const { return 0; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dbBinnedAreaCollector.h"
|
||||||
|
#include "dbEdgeProcessor.h"
|
||||||
|
#include "tlUnitTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class AreaReceiver
|
||||||
|
: public db::binned_area_receiver<double>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||||
|
|
||||||
|
AreaReceiver () : m_sum (0.0) { }
|
||||||
|
|
||||||
|
virtual void add_area (area_type area, const double &value)
|
||||||
|
{
|
||||||
|
m_sum += value * area;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get () const { return m_sum; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
double m_sum;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(1_Basic)
|
||||||
|
{
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (500, 1000, 1500, 3000)), 1);
|
||||||
|
|
||||||
|
// set up an XOR mask where 1-vs-0 is counted twice
|
||||||
|
tl::bit_set_map<double> bsm;
|
||||||
|
tl::BitSetMask bs0;
|
||||||
|
bs0.set (0, tl::BitSetMask::True);
|
||||||
|
bs0.set (1, tl::BitSetMask::False);
|
||||||
|
tl::BitSetMask bs1;
|
||||||
|
bs1.set (0, tl::BitSetMask::False);
|
||||||
|
bs1.set (1, tl::BitSetMask::True);
|
||||||
|
bsm.insert (bs0, 1.0);
|
||||||
|
bsm.insert (bs1, 2.0);
|
||||||
|
bsm.sort ();
|
||||||
|
|
||||||
|
AreaReceiver rec;
|
||||||
|
db::binned_area_collector<double> coll (bsm, rec);
|
||||||
|
ep.process (coll, coll);
|
||||||
|
|
||||||
|
EXPECT_EQ (rec.get (), 4500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(2_ShapesGetMerged)
|
||||||
|
{
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, -1000, 1000, 1000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (500, 1000, 1500, 3000)), 1);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (1000, 1000, 1500, 3000)), 1);
|
||||||
|
|
||||||
|
// set up an XOR mask where 1-vs-0 is counted twice
|
||||||
|
tl::bit_set_map<double> bsm;
|
||||||
|
tl::BitSetMask bs0;
|
||||||
|
bs0.set (0, tl::BitSetMask::True);
|
||||||
|
bs0.set (1, tl::BitSetMask::False);
|
||||||
|
tl::BitSetMask bs1;
|
||||||
|
bs1.set (0, tl::BitSetMask::False);
|
||||||
|
bs1.set (1, tl::BitSetMask::True);
|
||||||
|
bsm.insert (bs0, 1.0);
|
||||||
|
bsm.insert (bs1, 2.0);
|
||||||
|
bsm.sort ();
|
||||||
|
|
||||||
|
AreaReceiver rec;
|
||||||
|
db::binned_area_collector<double> coll (bsm, rec);
|
||||||
|
ep.process (coll, coll);
|
||||||
|
|
||||||
|
EXPECT_EQ (rec.get (), 5500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3_TouchingOnly)
|
||||||
|
{
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, -1000, 1000, 1000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (1000, 0, 2000, 2000)), 1);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (1000, 500, 1500, 1500)), 1);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, 0, 1000, 1000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (1500, 500, 2000, 2000)), 1);
|
||||||
|
|
||||||
|
// set up an XOR mask where 1-vs-0 is counted twice
|
||||||
|
tl::bit_set_map<double> bsm;
|
||||||
|
tl::BitSetMask bs0;
|
||||||
|
bs0.set (0, tl::BitSetMask::True);
|
||||||
|
bs0.set (1, tl::BitSetMask::False);
|
||||||
|
tl::BitSetMask bs1;
|
||||||
|
bs1.set (0, tl::BitSetMask::False);
|
||||||
|
bs1.set (1, tl::BitSetMask::True);
|
||||||
|
bsm.insert (bs0, 1.0);
|
||||||
|
bsm.insert (bs1, 2.0);
|
||||||
|
bsm.sort ();
|
||||||
|
|
||||||
|
AreaReceiver rec;
|
||||||
|
db::binned_area_collector<double> coll (bsm, rec);
|
||||||
|
ep.process (coll, coll);
|
||||||
|
|
||||||
|
EXPECT_EQ (rec.get (), 6000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(4_PlainAreaApproximation)
|
||||||
|
{
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, -1000, 1000, 1000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (500, 1000, 1500, 3000)), 1);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)), 0);
|
||||||
|
ep.insert (db::SimplePolygon (db::Box (1000, 1000, 1500, 3000)), 1);
|
||||||
|
|
||||||
|
tl::bit_set_map<double> bsm;
|
||||||
|
bsm.insert (tl::BitSetMask (), 1.0);
|
||||||
|
bsm.sort ();
|
||||||
|
|
||||||
|
AreaReceiver rec;
|
||||||
|
db::binned_area_collector<double> coll (bsm, rec);
|
||||||
|
ep.process (coll, coll);
|
||||||
|
|
||||||
|
EXPECT_EQ (rec.get (), 4500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -7,6 +7,7 @@ TARGET = db_tests
|
||||||
include($$PWD/../../lib_ut.pri)
|
include($$PWD/../../lib_ut.pri)
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
|
dbBinnedAreaCollectorTests.cc \
|
||||||
dbCompoundOperationTests.cc \
|
dbCompoundOperationTests.cc \
|
||||||
dbEdgeNeighborhoodTests.cc \
|
dbEdgeNeighborhoodTests.cc \
|
||||||
dbFillToolTests.cc \
|
dbFillToolTests.cc \
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ FORMS =
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
tlAssert.cc \
|
tlAssert.cc \
|
||||||
tlBase64.cc \
|
tlBase64.cc \
|
||||||
|
tlBitSet.cc \
|
||||||
|
tlBitSetMap.cc \
|
||||||
|
tlBitSetMask.cc \
|
||||||
tlColor.cc \
|
tlColor.cc \
|
||||||
tlClassRegistry.cc \
|
tlClassRegistry.cc \
|
||||||
tlCopyOnWrite.cc \
|
tlCopyOnWrite.cc \
|
||||||
|
|
@ -62,6 +65,9 @@ HEADERS = \
|
||||||
tlAlgorithm.h \
|
tlAlgorithm.h \
|
||||||
tlAssert.h \
|
tlAssert.h \
|
||||||
tlBase64.h \
|
tlBase64.h \
|
||||||
|
tlBitSet.h \
|
||||||
|
tlBitSetMap.h \
|
||||||
|
tlBitSetMask.h \
|
||||||
tlColor.h \
|
tlColor.h \
|
||||||
tlClassRegistry.h \
|
tlClassRegistry.h \
|
||||||
tlCopyOnWrite.h \
|
tlCopyOnWrite.h \
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,244 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
|
||||||
|
#include "tlBitSet.h"
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
static inline unsigned int nwords (BitSet::size_type size)
|
||||||
|
{
|
||||||
|
return (size + (sizeof (BitSet::data_type) * 8 - 1)) / (sizeof (BitSet::data_type) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int word (BitSet::size_type index)
|
||||||
|
{
|
||||||
|
return index / (sizeof (BitSet::data_type) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int bit (BitSet::size_type index)
|
||||||
|
{
|
||||||
|
// first bit is the highest bit, so that comparing the uint's is good enough
|
||||||
|
// for lexical order.
|
||||||
|
return 31 - (index % (sizeof (BitSet::data_type) * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet::BitSet ()
|
||||||
|
: mp_data (0), m_size (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet::BitSet (const std::string &s)
|
||||||
|
: mp_data (0), m_size (0)
|
||||||
|
{
|
||||||
|
index_type bit = 0;
|
||||||
|
for (const char *cp = s.c_str (); *cp; ++cp, ++bit) {
|
||||||
|
set_value (bit, *cp == '1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet::BitSet (const BitSet &other)
|
||||||
|
: mp_data (0), m_size (0)
|
||||||
|
{
|
||||||
|
operator= (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet::BitSet (BitSet &&other)
|
||||||
|
: mp_data (0), m_size (0)
|
||||||
|
{
|
||||||
|
operator= (std::move (other));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
BitSet::to_string () const
|
||||||
|
{
|
||||||
|
std::string r;
|
||||||
|
r.reserve (m_size);
|
||||||
|
|
||||||
|
for (index_type i = 0; i < m_size; ++i) {
|
||||||
|
r += operator[] (i) ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet::~BitSet ()
|
||||||
|
{
|
||||||
|
clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet &
|
||||||
|
BitSet::operator= (const BitSet &other)
|
||||||
|
{
|
||||||
|
if (&other != this) {
|
||||||
|
|
||||||
|
clear ();
|
||||||
|
|
||||||
|
// reallocate
|
||||||
|
m_size = other.m_size;
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
mp_data = new data_type[words];
|
||||||
|
data_type *t = mp_data;
|
||||||
|
data_type *s = other.mp_data;
|
||||||
|
for (unsigned int i = 0; i < words; ++i) {
|
||||||
|
*t++ = *s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet &
|
||||||
|
BitSet::operator= (BitSet &&other)
|
||||||
|
{
|
||||||
|
if (&other != this) {
|
||||||
|
swap (other);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSet::clear ()
|
||||||
|
{
|
||||||
|
if (mp_data) {
|
||||||
|
delete [] mp_data;
|
||||||
|
}
|
||||||
|
mp_data = 0;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSet::resize (size_type size)
|
||||||
|
{
|
||||||
|
if (size > m_size) {
|
||||||
|
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
unsigned int new_words = nwords (size);
|
||||||
|
|
||||||
|
if (new_words > words) {
|
||||||
|
|
||||||
|
// reallocate
|
||||||
|
data_type *new_data = new data_type[new_words];
|
||||||
|
data_type *t = new_data;
|
||||||
|
data_type *s = mp_data;
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < words; ++i) {
|
||||||
|
*t++ = *s++;
|
||||||
|
}
|
||||||
|
for (; i < new_words; ++i) {
|
||||||
|
*t++ = 0;
|
||||||
|
}
|
||||||
|
delete mp_data;
|
||||||
|
mp_data = new_data;
|
||||||
|
m_size = size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BitSet::operator== (const BitSet &other) const
|
||||||
|
{
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
unsigned int other_words = nwords (other.m_size);
|
||||||
|
|
||||||
|
const data_type *p = mp_data;
|
||||||
|
const data_type *op = other.mp_data;
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < words && i < other_words; ++i) {
|
||||||
|
if (*p++ != *op++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < words; ++i) {
|
||||||
|
if (*p++ != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < other_words; ++i) {
|
||||||
|
if (0 != *op++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BitSet::operator< (const BitSet &other) const
|
||||||
|
{
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
unsigned int other_words = nwords (other.m_size);
|
||||||
|
|
||||||
|
const data_type *p = mp_data;
|
||||||
|
const data_type *op = other.mp_data;
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < words && i < other_words; ++i, ++p, ++op) {
|
||||||
|
if (*p != *op) {
|
||||||
|
return *p < *op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < other_words; ++i, ++op) {
|
||||||
|
if (0 != *op) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSet::set (index_type index)
|
||||||
|
{
|
||||||
|
unsigned int wi = word (index);
|
||||||
|
if (wi >= nwords (m_size)) {
|
||||||
|
resize (index + 1);
|
||||||
|
} else if (index >= m_size) {
|
||||||
|
m_size = index + 1;
|
||||||
|
}
|
||||||
|
mp_data [wi] |= (1 << bit (index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSet::reset (index_type index)
|
||||||
|
{
|
||||||
|
if (index < m_size) {
|
||||||
|
unsigned int wi = word (index);
|
||||||
|
mp_data [wi] &= ~(1 << bit (index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BitSet::operator[] (index_type index) const
|
||||||
|
{
|
||||||
|
if (index < m_size) {
|
||||||
|
unsigned int wi = word (index);
|
||||||
|
return (mp_data [wi] & (1 << bit (index))) != 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,251 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_tlBitSet
|
||||||
|
#define HDR_tlBitSet
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A bit set
|
||||||
|
*
|
||||||
|
* This object can store a set of n bits, each being true or false.
|
||||||
|
* Essentially is it like a vector<bool>, but optimized to cooperate
|
||||||
|
* with tl::BitSetMap and tl::BitSetMatch.
|
||||||
|
*
|
||||||
|
* Allocation is dynamic when a bit is accessed for write. Bits beyond the
|
||||||
|
* allocated size are treated as "false" or zero.
|
||||||
|
*/
|
||||||
|
class TL_PUBLIC BitSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef unsigned int index_type;
|
||||||
|
typedef unsigned int size_type;
|
||||||
|
typedef uint32_t data_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default constructor: creates an empty bit set
|
||||||
|
*/
|
||||||
|
BitSet ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates and initializes a bit set from a range of indexes
|
||||||
|
* Every bit given by an index from the range is set.
|
||||||
|
*/
|
||||||
|
template <class Iter>
|
||||||
|
BitSet (Iter from, Iter to)
|
||||||
|
: mp_data (0), m_size (0)
|
||||||
|
{
|
||||||
|
set (from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a bit set from a string
|
||||||
|
*
|
||||||
|
* In the string, a '0' character is for False, '1' for True.
|
||||||
|
*/
|
||||||
|
BitSet (const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor
|
||||||
|
*/
|
||||||
|
BitSet (const BitSet &other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
|
BitSet (BitSet &&other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the bit set to a string
|
||||||
|
*/
|
||||||
|
std::string to_string () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
~BitSet ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assignment
|
||||||
|
*/
|
||||||
|
BitSet &operator= (const BitSet &other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move assignment
|
||||||
|
*/
|
||||||
|
BitSet &operator= (BitSet &&other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swaps the contents of this bit set with the other
|
||||||
|
*/
|
||||||
|
void swap (BitSet &other)
|
||||||
|
{
|
||||||
|
std::swap (mp_data, other.mp_data);
|
||||||
|
std::swap (m_size, other.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears this bit set
|
||||||
|
*/
|
||||||
|
void clear ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sizes the bit set to "size" bits
|
||||||
|
*
|
||||||
|
* New bits are set to false.
|
||||||
|
*/
|
||||||
|
void resize (size_type size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Equality
|
||||||
|
*/
|
||||||
|
bool operator== (const BitSet &other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inequality
|
||||||
|
*/
|
||||||
|
bool operator!= (const BitSet &other) const
|
||||||
|
{
|
||||||
|
return !operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Less operator
|
||||||
|
*
|
||||||
|
* The bits are compared in lexical order, first bit first.
|
||||||
|
*/
|
||||||
|
bool operator< (const BitSet &other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the given bit
|
||||||
|
*/
|
||||||
|
void set (index_type index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a range of bits
|
||||||
|
* The indexes are taken from the sequence delivered by the iterator.
|
||||||
|
*/
|
||||||
|
template <class Iter>
|
||||||
|
void set (Iter from, Iter to)
|
||||||
|
{
|
||||||
|
for (Iter i = from; i != to; ++i) {
|
||||||
|
set (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets the given bit
|
||||||
|
*/
|
||||||
|
void reset (index_type index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets a range of bits
|
||||||
|
* The indexes are taken from the sequence delivered by the iterator.
|
||||||
|
*/
|
||||||
|
template <class Iter>
|
||||||
|
void reset (Iter from, Iter to)
|
||||||
|
{
|
||||||
|
for (Iter i = from; i != to; ++i) {
|
||||||
|
reset (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the values for a given bit
|
||||||
|
*/
|
||||||
|
void set_value (index_type index, bool f)
|
||||||
|
{
|
||||||
|
if (f) {
|
||||||
|
set (index);
|
||||||
|
} else {
|
||||||
|
reset (index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the values for a range of bits
|
||||||
|
* The indexes are taken from the sequence delivered by the iterator.
|
||||||
|
*/
|
||||||
|
template <class Iter>
|
||||||
|
void set_value (Iter from, Iter to, bool f)
|
||||||
|
{
|
||||||
|
for (Iter i = from; i != to; ++i) {
|
||||||
|
set_value (*i, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a bit from the given index
|
||||||
|
*/
|
||||||
|
bool operator[] (index_type index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a value indicating whether the set is empty
|
||||||
|
*
|
||||||
|
* "empty" means, no bits have been written yet. "empty" does NOT mean
|
||||||
|
* all bits are zero.
|
||||||
|
*/
|
||||||
|
bool is_empty () const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the number of bits stored
|
||||||
|
*
|
||||||
|
* The number of bits is the highest bit written so far.
|
||||||
|
*/
|
||||||
|
size_type size () const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class BitSetMask;
|
||||||
|
|
||||||
|
data_type *mp_data;
|
||||||
|
size_type m_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
inline void
|
||||||
|
swap (tl::BitSet &a, tl::BitSet &b)
|
||||||
|
{
|
||||||
|
a.swap (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
|
||||||
|
#include "tlBitSetMap.h"
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,374 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_tlBitSetMap
|
||||||
|
#define HDR_tlBitSetMap
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
#include "tlBitSetMask.h"
|
||||||
|
#include "tlBitSet.h"
|
||||||
|
#include "tlAssert.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
struct TL_PUBLIC_TEMPLATE bit_set_mask_node
|
||||||
|
{
|
||||||
|
bit_set_mask_node ()
|
||||||
|
: mask (), next (0), value ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
tl::BitSetMask mask;
|
||||||
|
size_t next;
|
||||||
|
Value value;
|
||||||
|
|
||||||
|
void swap (bit_set_mask_node<Value> &other)
|
||||||
|
{
|
||||||
|
std::swap (mask, other.mask);
|
||||||
|
std::swap (next, other.next);
|
||||||
|
std::swap (value, other.value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
class TL_PUBLIC_TEMPLATE bit_set_mask_compare
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bit_set_mask_compare (tl::BitSetMask::index_type bit, tl::BitSetMask::mask_type mask)
|
||||||
|
: m_bit (bit), m_mask (mask)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator() (const bit_set_mask_node<Value> &node) const
|
||||||
|
{
|
||||||
|
return node.mask [m_bit] < m_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
tl::BitSetMask::index_type m_bit;
|
||||||
|
tl::BitSetMask::mask_type m_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
inline void
|
||||||
|
swap (tl::bit_set_mask_node<Value> &a, tl::bit_set_mask_node<Value> &b)
|
||||||
|
{
|
||||||
|
a.swap (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A bit set map
|
||||||
|
*
|
||||||
|
* This specialized map stores tl::BitSetMask keys and corresponding values.
|
||||||
|
* tl::BitSet objects can be used to retrieve values. Masks may overlap, hence
|
||||||
|
* multiple matches are possible. The "lookup" method employs a visitor
|
||||||
|
* pattern to deliver these multiple matches.
|
||||||
|
*
|
||||||
|
* In order to use the map, it first has to be sorted. Insert masks using
|
||||||
|
* "insert" and do a "sort" before using "lookup".
|
||||||
|
*/
|
||||||
|
template <class Value>
|
||||||
|
class TL_PUBLIC_TEMPLATE bit_set_map
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::vector<bit_set_mask_node<Value> > node_list;
|
||||||
|
typedef typename node_list::const_iterator const_iterator;
|
||||||
|
typedef typename node_list::iterator iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default constructor: creates an empty bit set
|
||||||
|
*/
|
||||||
|
bit_set_map ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor
|
||||||
|
*/
|
||||||
|
bit_set_map (const bit_set_map &other)
|
||||||
|
{
|
||||||
|
operator= (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
|
bit_set_map (bit_set_map &&other)
|
||||||
|
{
|
||||||
|
operator= (std::move (other));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assignment
|
||||||
|
*/
|
||||||
|
bit_set_map &operator= (const bit_set_map &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
m_nodes = other.m_nodes;
|
||||||
|
m_sorted = other.m_sorted;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move assignment
|
||||||
|
*/
|
||||||
|
bit_set_map &operator= (bit_set_map &&other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
swap (other);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swaps the contents of this bit set with the other
|
||||||
|
*/
|
||||||
|
void swap (bit_set_map &other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
m_nodes.swap (other.m_nodes);
|
||||||
|
std::swap (m_sorted, other.m_sorted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears this map
|
||||||
|
*/
|
||||||
|
void clear ()
|
||||||
|
{
|
||||||
|
m_nodes.clear ();
|
||||||
|
m_sorted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reserves "size" entries
|
||||||
|
*
|
||||||
|
* Use this method to specify the intended size of the map.
|
||||||
|
* This optimizes performance and memory allocation.
|
||||||
|
*/
|
||||||
|
void reserve (size_t n)
|
||||||
|
{
|
||||||
|
m_nodes.reserve (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inserts an item into the map
|
||||||
|
*/
|
||||||
|
void insert (const tl::BitSetMask &mask, const Value &value)
|
||||||
|
{
|
||||||
|
m_nodes.push_back (tl::bit_set_mask_node<Value> ());
|
||||||
|
m_nodes.back ().mask = mask;
|
||||||
|
m_nodes.back ().next = 0;
|
||||||
|
m_nodes.back ().value = value;
|
||||||
|
|
||||||
|
m_sorted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sorts the map
|
||||||
|
*
|
||||||
|
* "sort" needs to be called before "lookup" can be used.
|
||||||
|
*/
|
||||||
|
void sort ()
|
||||||
|
{
|
||||||
|
if (! m_sorted) {
|
||||||
|
if (! m_nodes.empty ()) {
|
||||||
|
m_nodes.front ().next = m_nodes.size ();
|
||||||
|
sort_range (0, m_nodes.begin (), m_nodes.end ());
|
||||||
|
}
|
||||||
|
m_sorted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a value indicating whether the set is empty
|
||||||
|
*
|
||||||
|
* "empty" means, no bits have been written yet. "empty" does NOT mean
|
||||||
|
* all masks are of some specific value.
|
||||||
|
*/
|
||||||
|
bool is_empty () const
|
||||||
|
{
|
||||||
|
return m_nodes.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the number of bits for the mask stored
|
||||||
|
*
|
||||||
|
* The number of bits is the highest bit written so far.
|
||||||
|
*/
|
||||||
|
size_t size () const
|
||||||
|
{
|
||||||
|
return m_nodes.size ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Looks up items by bit set
|
||||||
|
*
|
||||||
|
* For each item found, the value is delivered through the
|
||||||
|
* Inserter provided.
|
||||||
|
*
|
||||||
|
* The return value is true, if any value has been found.
|
||||||
|
*/
|
||||||
|
template <class Inserter>
|
||||||
|
bool lookup (const tl::BitSet &bit_set, Inserter inserter) const
|
||||||
|
{
|
||||||
|
tl_assert (m_sorted);
|
||||||
|
return partial_lookup (0, m_nodes.begin (), m_nodes.end (), bit_set, inserter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Begin iterator
|
||||||
|
*/
|
||||||
|
iterator begin ()
|
||||||
|
{
|
||||||
|
return m_nodes.begin ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief End iterator
|
||||||
|
*/
|
||||||
|
iterator end ()
|
||||||
|
{
|
||||||
|
return m_nodes.end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Begin iterator (const version)
|
||||||
|
*/
|
||||||
|
const_iterator begin () const
|
||||||
|
{
|
||||||
|
return m_nodes.begin ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief End iterator (const version)
|
||||||
|
*/
|
||||||
|
const_iterator end () const
|
||||||
|
{
|
||||||
|
return m_nodes.end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
node_list m_nodes;
|
||||||
|
bool m_sorted;
|
||||||
|
|
||||||
|
void sort_range (tl::BitSetMask::index_type bit, iterator from, iterator to)
|
||||||
|
{
|
||||||
|
if (from == to) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case of identical entries which creates a sequence of
|
||||||
|
// single entries
|
||||||
|
bool all_same = true;
|
||||||
|
for (auto i = from + 1; i != to && all_same; ++i) {
|
||||||
|
if (i->mask != from->mask) {
|
||||||
|
all_same = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_same) {
|
||||||
|
// this is also the case for a single element
|
||||||
|
for (auto i = from + 1; i != to; ++i) {
|
||||||
|
i->next = 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have at least one element. The first one is taken for the previous level node, so we start partitioning
|
||||||
|
// at the second node
|
||||||
|
++from;
|
||||||
|
|
||||||
|
auto middle_false = std::partition (from, to, tl::bit_set_mask_compare<Value> (bit, tl::BitSetMask::False));
|
||||||
|
auto middle_true = std::partition (middle_false, to, tl::bit_set_mask_compare<Value> (bit, tl::BitSetMask::True));
|
||||||
|
auto middle_never = std::partition (middle_true, to, tl::bit_set_mask_compare<Value> (bit, tl::BitSetMask::Never));
|
||||||
|
|
||||||
|
from->next = middle_false - from;
|
||||||
|
if (middle_false != to) {
|
||||||
|
middle_false->next = middle_true - middle_false;
|
||||||
|
}
|
||||||
|
if (middle_true != to) {
|
||||||
|
middle_true->next = middle_never - middle_true;
|
||||||
|
}
|
||||||
|
if (middle_never != to) {
|
||||||
|
middle_never->next = to - middle_never;
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_range (bit + 1, from, middle_false);
|
||||||
|
sort_range (bit + 1, middle_false, middle_true);
|
||||||
|
sort_range (bit + 1, middle_true, middle_never);
|
||||||
|
sort_range (bit + 1, middle_never, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Inserter>
|
||||||
|
bool partial_lookup (tl::BitSetMask::index_type bit, const_iterator from, const_iterator to, const tl::BitSet &bit_set, Inserter inserter) const
|
||||||
|
{
|
||||||
|
if (from == to) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool any = false;
|
||||||
|
if (from->mask.match (bit_set)) {
|
||||||
|
*inserter++ = from->value;
|
||||||
|
any = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool b = bit_set [bit];
|
||||||
|
|
||||||
|
auto i = ++from;
|
||||||
|
while (i != to) {
|
||||||
|
auto m = i->mask [bit];
|
||||||
|
if (m == tl::BitSetMask::Any || (m == tl::BitSetMask::True && b) || (m == tl::BitSetMask::False && !b)) {
|
||||||
|
if (partial_lookup (bit + 1, i, i + i->next, bit_set, inserter)) {
|
||||||
|
any = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i->next == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += i->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return any;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,373 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
|
||||||
|
#include "tlBitSetMask.h"
|
||||||
|
#include "tlBitSet.h"
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
static inline unsigned int nwords (BitSetMask::size_type size)
|
||||||
|
{
|
||||||
|
return (size + (sizeof (BitSetMask::data_type) * 8 - 1)) / (sizeof (BitSetMask::data_type) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int word (BitSetMask::size_type index)
|
||||||
|
{
|
||||||
|
return index / (sizeof (BitSetMask::data_type) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int bit (BitSetMask::size_type index)
|
||||||
|
{
|
||||||
|
// first bit is the highest bit, so that comparing the uint's is good enough
|
||||||
|
// for lexical order.
|
||||||
|
return 31 - (index % (sizeof (BitSetMask::data_type) * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask::BitSetMask ()
|
||||||
|
: mp_data0 (0), mp_data1 (0), m_size (0)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask::BitSetMask (const std::string &s)
|
||||||
|
: mp_data0 (0), mp_data1 (0), m_size (0)
|
||||||
|
{
|
||||||
|
index_type bit = 0;
|
||||||
|
for (const char *cp = s.c_str (); *cp; ++cp, ++bit) {
|
||||||
|
mask_type m = Any;
|
||||||
|
if (*cp == '0') {
|
||||||
|
m = False;
|
||||||
|
} else if (*cp == '1') {
|
||||||
|
m = True;
|
||||||
|
} else if (*cp == '-') {
|
||||||
|
m = Never;
|
||||||
|
}
|
||||||
|
set (bit, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask::BitSetMask (const BitSetMask &other)
|
||||||
|
: mp_data0 (0), mp_data1 (0), m_size (0)
|
||||||
|
{
|
||||||
|
operator= (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask::BitSetMask (BitSetMask &&other)
|
||||||
|
: mp_data0 (0), mp_data1 (0), m_size (0)
|
||||||
|
{
|
||||||
|
operator= (std::move (other));
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask::~BitSetMask ()
|
||||||
|
{
|
||||||
|
clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
BitSetMask::to_string () const
|
||||||
|
{
|
||||||
|
std::string r;
|
||||||
|
r.reserve (m_size);
|
||||||
|
|
||||||
|
for (index_type i = 0; i < m_size; ++i) {
|
||||||
|
switch (operator[] (i)) {
|
||||||
|
case False:
|
||||||
|
r += '0';
|
||||||
|
break;
|
||||||
|
case True:
|
||||||
|
r += '1';
|
||||||
|
break;
|
||||||
|
case Never:
|
||||||
|
r += '-';
|
||||||
|
break;
|
||||||
|
case Any:
|
||||||
|
default:
|
||||||
|
r += 'X';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask &
|
||||||
|
BitSetMask::operator= (const BitSetMask &other)
|
||||||
|
{
|
||||||
|
if (&other != this) {
|
||||||
|
|
||||||
|
clear ();
|
||||||
|
|
||||||
|
// reallocate
|
||||||
|
m_size = other.m_size;
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
mp_data0 = new data_type[words];
|
||||||
|
mp_data1 = new data_type[words];
|
||||||
|
data_type *t0 = mp_data0;
|
||||||
|
data_type *s0 = other.mp_data0;
|
||||||
|
data_type *t1 = mp_data1;
|
||||||
|
data_type *s1 = other.mp_data1;
|
||||||
|
for (unsigned int i = 0; i < words; ++i) {
|
||||||
|
*t0++ = *s0++;
|
||||||
|
*t1++ = *s1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask &
|
||||||
|
BitSetMask::operator= (BitSetMask &&other)
|
||||||
|
{
|
||||||
|
if (&other != this) {
|
||||||
|
swap (other);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSetMask::clear ()
|
||||||
|
{
|
||||||
|
if (mp_data0) {
|
||||||
|
delete [] mp_data0;
|
||||||
|
}
|
||||||
|
mp_data0 = 0;
|
||||||
|
if (mp_data1) {
|
||||||
|
delete [] mp_data1;
|
||||||
|
}
|
||||||
|
mp_data1 = 0;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSetMask::resize (size_type size)
|
||||||
|
{
|
||||||
|
if (size > m_size) {
|
||||||
|
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
unsigned int new_words = nwords (size);
|
||||||
|
|
||||||
|
if (new_words > words) {
|
||||||
|
|
||||||
|
// reallocate
|
||||||
|
data_type *new_data0 = new data_type[new_words];
|
||||||
|
data_type *new_data1 = new data_type[new_words];
|
||||||
|
data_type *t0 = new_data0;
|
||||||
|
data_type *s0 = mp_data0;
|
||||||
|
data_type *t1 = new_data1;
|
||||||
|
data_type *s1 = mp_data1;
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < words; ++i) {
|
||||||
|
*t0++ = *s0++;
|
||||||
|
*t1++ = *s1++;
|
||||||
|
}
|
||||||
|
for (; i < new_words; ++i) {
|
||||||
|
// corresponds to "Any"
|
||||||
|
*t0++ = 0;
|
||||||
|
*t1++ = 0;
|
||||||
|
}
|
||||||
|
delete mp_data0;
|
||||||
|
mp_data0 = new_data0;
|
||||||
|
delete mp_data1;
|
||||||
|
mp_data1 = new_data1;
|
||||||
|
m_size = size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BitSetMask::operator== (const BitSetMask &other) const
|
||||||
|
{
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
unsigned int other_words = nwords (other.m_size);
|
||||||
|
|
||||||
|
const data_type *p0 = mp_data0;
|
||||||
|
const data_type *p1 = mp_data1;
|
||||||
|
const data_type *op0 = other.mp_data0;
|
||||||
|
const data_type *op1 = other.mp_data1;
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < words && i < other_words; ++i) {
|
||||||
|
if (*p0++ != *op0++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (*p1++ != *op1++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < words; ++i) {
|
||||||
|
if (*p0++ != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (*p1++ != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; i < other_words; ++i) {
|
||||||
|
if (0 != *op0++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (0 != *op1++) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the most significant bit of a bit set
|
||||||
|
*
|
||||||
|
* For example b:00101101 will give b:00100000.
|
||||||
|
*/
|
||||||
|
static inline BitSetMask::data_type msb_only (BitSetMask::data_type value)
|
||||||
|
{
|
||||||
|
const unsigned int smax = sizeof (BitSetMask::data_type) * 8;
|
||||||
|
|
||||||
|
BitSetMask::data_type m = value;
|
||||||
|
for (unsigned int s = 1; s < smax; s *= 2) {
|
||||||
|
m |= (m >> s);
|
||||||
|
}
|
||||||
|
return value & ~(m >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BitSetMask::operator< (const BitSetMask &other) const
|
||||||
|
{
|
||||||
|
unsigned int words = nwords (m_size);
|
||||||
|
unsigned int other_words = nwords (other.m_size);
|
||||||
|
|
||||||
|
const data_type *p0 = mp_data0;
|
||||||
|
const data_type *p1 = mp_data1;
|
||||||
|
const data_type *op0 = other.mp_data0;
|
||||||
|
const data_type *op1 = other.mp_data1;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < words && i < other_words; ++i, ++p0, ++p1, ++op0, ++op1) {
|
||||||
|
data_type diff = (*p0 ^ *op0) | (*p1 ^ *op1);
|
||||||
|
if (diff) {
|
||||||
|
// compare the most significant position of the differences by value
|
||||||
|
data_type mb = msb_only (diff);
|
||||||
|
unsigned int m = ((*p0 & mb) != 0 ? 1 : 0) + ((*p1 & mb) != 0 ? 2 : 0);
|
||||||
|
unsigned int om = ((*op0 & mb) != 0 ? 1 : 0) + ((*op1 & mb) != 0 ? 2 : 0);
|
||||||
|
return m < om;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the remaining part of other is simply checked for
|
||||||
|
// not being zero
|
||||||
|
for (; i < other_words; ++i, ++op0, ++op1) {
|
||||||
|
if (0 != *op0 || 0 != *op1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BitSetMask::set (index_type index, mask_type mask)
|
||||||
|
{
|
||||||
|
if (index >= m_size && mask == Any) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int wi = word (index);
|
||||||
|
if (wi >= nwords (m_size)) {
|
||||||
|
resize (index + 1);
|
||||||
|
} else if (index >= m_size) {
|
||||||
|
m_size = index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mi = (unsigned int) mask;
|
||||||
|
data_type bm = (1 << bit (index));
|
||||||
|
if (mi & 1) {
|
||||||
|
mp_data0 [wi] |= bm;
|
||||||
|
} else {
|
||||||
|
mp_data0 [wi] &= ~bm;
|
||||||
|
}
|
||||||
|
if (mi & 2) {
|
||||||
|
mp_data1 [wi] |= bm;
|
||||||
|
} else {
|
||||||
|
mp_data1 [wi] &= ~bm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSetMask::mask_type
|
||||||
|
BitSetMask::operator[] (index_type index) const
|
||||||
|
{
|
||||||
|
if (index < m_size) {
|
||||||
|
unsigned int wi = word (index);
|
||||||
|
data_type bm = (1 << bit (index));
|
||||||
|
unsigned int mi = ((mp_data0 [wi] & bm) != 0 ? 1 : 0) | ((mp_data1 [wi] & bm) != 0 ? 2 : 0);
|
||||||
|
return mask_type (mi);
|
||||||
|
} else {
|
||||||
|
return Any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BitSetMask::match (const tl::BitSet &bs) const
|
||||||
|
{
|
||||||
|
unsigned int nw_bs = nwords (bs.m_size);
|
||||||
|
unsigned int nw = nwords (m_size);
|
||||||
|
|
||||||
|
const tl::BitSet::data_type *d0 = mp_data0, *d1 = mp_data1;
|
||||||
|
const tl::BitSet::data_type *s = bs.mp_data;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < nw; ++i, ++d0, ++d1) {
|
||||||
|
|
||||||
|
tl::BitSet::data_type d = i < nw_bs ? *s++ : 0;
|
||||||
|
|
||||||
|
tl::BitSet::data_type invalid = 0;
|
||||||
|
if (i >= nw_bs) {
|
||||||
|
invalid = ~invalid;
|
||||||
|
} else if (bs.m_size < (i + 1) * (sizeof (tl::BitSet::data_type) * 8)) {
|
||||||
|
invalid = (1 << ((i + 1) * (sizeof (tl::BitSet::data_type) * 8) - bs.m_size)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "never" matches no valid bit ("never" is: d0 and d1 bits are ones)
|
||||||
|
if (((*d0 & *d1) & ~invalid) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A "true" in place of "false expected" gives "no match"
|
||||||
|
if ((*d0 & ~*d1 & d) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// A "false" in place of "true expected" gives "no match"
|
||||||
|
if ((*d1 & ~*d0 & ~d) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// as "not set" corresponds to "Any", we can stop here and have a match.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_tlBitSetMask
|
||||||
|
#define HDR_tlBitSetMask
|
||||||
|
|
||||||
|
#include "tlCommon.h"
|
||||||
|
#include "tlBitSet.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A bit set
|
||||||
|
*
|
||||||
|
* This object can store a mask for a bit set.
|
||||||
|
* Each element of the mask corresponds to one bit. Each element can be "True"
|
||||||
|
* (matching to true), "False" (matching to false), "Any" matching to true
|
||||||
|
* or false and "Never" matches neither to true nor false.
|
||||||
|
*
|
||||||
|
* A bit set match can be matched against a bit set and will return true if
|
||||||
|
* the bit set corresponds to the mask.
|
||||||
|
*
|
||||||
|
* Allocation is dynamic when a mask element is accessed for write. Bits beyond the
|
||||||
|
* allocated size are treated as "Any".
|
||||||
|
*/
|
||||||
|
class TL_PUBLIC BitSetMask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef enum { Any = 0, False = 1, True = 2, Never = 3 } mask_type;
|
||||||
|
|
||||||
|
typedef tl::BitSet::index_type index_type;
|
||||||
|
typedef tl::BitSet::size_type size_type;
|
||||||
|
typedef tl::BitSet::data_type data_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default constructor: creates an empty bit set
|
||||||
|
*/
|
||||||
|
BitSetMask ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a bit set mask from a string
|
||||||
|
*
|
||||||
|
* In the string, a '0' character is for False, '1' for True, 'X' for Any and '-' for Never.
|
||||||
|
*/
|
||||||
|
BitSetMask (const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy constructor
|
||||||
|
*/
|
||||||
|
BitSetMask (const BitSetMask &other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
|
BitSetMask (BitSetMask &&other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
~BitSetMask ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the mask to a string
|
||||||
|
*/
|
||||||
|
std::string to_string () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assignment
|
||||||
|
*/
|
||||||
|
BitSetMask &operator= (const BitSetMask &other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move assignment
|
||||||
|
*/
|
||||||
|
BitSetMask &operator= (BitSetMask &&other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swaps the contents of this bit set with the other
|
||||||
|
*/
|
||||||
|
void swap (BitSetMask &other)
|
||||||
|
{
|
||||||
|
std::swap (mp_data0, other.mp_data0);
|
||||||
|
std::swap (mp_data1, other.mp_data1);
|
||||||
|
std::swap (m_size, other.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears this bit set
|
||||||
|
*/
|
||||||
|
void clear ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sizes the bit set to "size" bits
|
||||||
|
*
|
||||||
|
* New bits are set to false.
|
||||||
|
*/
|
||||||
|
void resize (size_type size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Equality
|
||||||
|
*/
|
||||||
|
bool operator== (const BitSetMask &other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inequality
|
||||||
|
*/
|
||||||
|
bool operator!= (const BitSetMask &other) const
|
||||||
|
{
|
||||||
|
return !operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Less operator
|
||||||
|
*
|
||||||
|
* The bits are compared in lexical order, first bit first.
|
||||||
|
*/
|
||||||
|
bool operator< (const BitSetMask &other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the mask for the given bit
|
||||||
|
*/
|
||||||
|
void set (index_type index, mask_type mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a mask from the given bit
|
||||||
|
*/
|
||||||
|
mask_type operator[] (index_type index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a value indicating whether the set is empty
|
||||||
|
*
|
||||||
|
* "empty" means, no bits have been written yet. "empty" does NOT mean
|
||||||
|
* all masks are of some specific value.
|
||||||
|
*/
|
||||||
|
bool is_empty () const
|
||||||
|
{
|
||||||
|
return m_size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the number of bits for the mask stored
|
||||||
|
*
|
||||||
|
* The number of bits is the highest bit written so far.
|
||||||
|
*/
|
||||||
|
size_type size () const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Matches the given bit set against this mask
|
||||||
|
*/
|
||||||
|
bool match (const tl::BitSet &) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
data_type *mp_data0, *mp_data1;
|
||||||
|
size_type m_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
inline void
|
||||||
|
swap (tl::BitSetMask &a, tl::BitSetMask &b)
|
||||||
|
{
|
||||||
|
a.swap (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,218 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tlBitSetMap.h"
|
||||||
|
#include "tlUnitTest.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
#include "tlTimer.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static tl::BitSet bs (const char *s)
|
||||||
|
{
|
||||||
|
return tl::BitSet (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tl::BitSetMask bsm (const char *s)
|
||||||
|
{
|
||||||
|
return tl::BitSetMask (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SetInserter
|
||||||
|
{
|
||||||
|
SetInserter (std::set<int> &s) : ps (&s) { }
|
||||||
|
|
||||||
|
SetInserter &operator++(int) { return *this; }
|
||||||
|
SetInserter &operator* () { return *this; }
|
||||||
|
|
||||||
|
SetInserter &operator= (int v) { ps->insert (v); return *this; }
|
||||||
|
|
||||||
|
std::set<int> *ps;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string s2s (const std::set<int> &values)
|
||||||
|
{
|
||||||
|
std::string res;
|
||||||
|
for (auto i = values.begin (); i != values.end (); ++i) {
|
||||||
|
if (!res.empty ()) {
|
||||||
|
res += ",";
|
||||||
|
}
|
||||||
|
res += tl::to_string (*i);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string match (const tl::bit_set_map<int> &bsm, const tl::BitSet &bs)
|
||||||
|
{
|
||||||
|
std::set<int> values;
|
||||||
|
bsm.lookup (bs, SetInserter (values));
|
||||||
|
return s2s (values);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
TEST(1_Basic)
|
||||||
|
{
|
||||||
|
tl::bit_set_map<int> map;
|
||||||
|
|
||||||
|
map.insert (bsm ("X10"), 1);
|
||||||
|
map.insert (bsm ("X10"), 11);
|
||||||
|
map.insert (bsm ("1"), 2);
|
||||||
|
map.insert (bsm ("101"), 3);
|
||||||
|
map.insert (bsm ("1X0"), 4);
|
||||||
|
map.insert (bsm ("110"), 5);
|
||||||
|
map.sort ();
|
||||||
|
|
||||||
|
EXPECT_EQ (match (map, bs ("")), "");
|
||||||
|
EXPECT_EQ (match (map, bs ("1")), "2,4");
|
||||||
|
EXPECT_EQ (match (map, bs ("110")), "1,2,4,5,11");
|
||||||
|
EXPECT_EQ (match (map, bs ("01")), "1,11");
|
||||||
|
EXPECT_EQ (match (map, bs ("010000")), "1,11");
|
||||||
|
|
||||||
|
map.insert (bsm (""), 0);
|
||||||
|
try {
|
||||||
|
match (map, bs (""));
|
||||||
|
EXPECT_EQ (true, false); // not sorted
|
||||||
|
} catch (...) { }
|
||||||
|
|
||||||
|
map.sort ();
|
||||||
|
EXPECT_EQ (match (map, bs ("")), "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string bitstr (unsigned int n, unsigned int nbits)
|
||||||
|
{
|
||||||
|
std::string r;
|
||||||
|
while (nbits > 0) {
|
||||||
|
r += ((n & 1) != 0 ? '1' : '0');
|
||||||
|
n >>= 1;
|
||||||
|
--nbits;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(2_Regular)
|
||||||
|
{
|
||||||
|
tl::bit_set_map<int> map;
|
||||||
|
|
||||||
|
unsigned int num = 10000;
|
||||||
|
unsigned int nbits = 20;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
|
map.insert (bsm (bitstr (i, nbits).c_str ()), int (i));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::SelfTimer timer ("sorting");
|
||||||
|
map.sort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::SelfTimer timer ("match method");
|
||||||
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
|
EXPECT_EQ (match (map, bs (bitstr (i, nbits).c_str ())), tl::to_string (i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force
|
||||||
|
{
|
||||||
|
tl::SelfTimer timer ("brute force");
|
||||||
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
|
tl::BitSet k = bs (bitstr (i, nbits).c_str ());
|
||||||
|
int value = 0;
|
||||||
|
for (auto j = map.begin (); j != map.end (); ++j) {
|
||||||
|
if (j->mask.match (k)) {
|
||||||
|
value = j->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_EQ (value, int (i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3_IrregularTest)
|
||||||
|
{
|
||||||
|
srand (0);
|
||||||
|
|
||||||
|
tl::bit_set_map<int> map;
|
||||||
|
|
||||||
|
unsigned int num = 10000;
|
||||||
|
unsigned int nbits_min = 10;
|
||||||
|
unsigned int nbits_max = 20;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
|
std::string s;
|
||||||
|
unsigned int n = nbits_min + (rand () % (nbits_max - nbits_min));
|
||||||
|
for (unsigned int j = 0; j < n; ++j) {
|
||||||
|
// this pattern gives roughly 5 matches per entry with 10k entries
|
||||||
|
s += "010101X"[rand () % 7];
|
||||||
|
}
|
||||||
|
map.insert (bsm (s.c_str ()), int (i));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<tl::BitSet> test_vectors;
|
||||||
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
|
std::string s;
|
||||||
|
unsigned int n = nbits_min + (rand () % (nbits_max - nbits_min));
|
||||||
|
for (unsigned int j = 0; j < n; ++j) {
|
||||||
|
s += "01"[rand () % 2];
|
||||||
|
}
|
||||||
|
test_vectors.push_back (bs (s.c_str ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::SelfTimer timer ("sorting");
|
||||||
|
map.sort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> matches;
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::SelfTimer timer ("match method");
|
||||||
|
for (auto i = test_vectors.begin (); i != test_vectors.end (); ++i) {
|
||||||
|
matches.push_back (match (map, *i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t max_matches = 0;
|
||||||
|
|
||||||
|
// brute force
|
||||||
|
{
|
||||||
|
tl::SelfTimer timer ("brute force");
|
||||||
|
for (auto i = test_vectors.begin (); i != test_vectors.end (); ++i) {
|
||||||
|
std::set<int> values;
|
||||||
|
for (auto j = map.begin (); j != map.end (); ++j) {
|
||||||
|
if (j->mask.match (*i)) {
|
||||||
|
values.insert(j->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_matches = std::max (max_matches, values.size ());
|
||||||
|
EXPECT_EQ (s2s (values), matches [i - test_vectors.begin ()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
tl::info << "Max. matches: " << max_matches;
|
||||||
|
EXPECT_EQ (max_matches > 5, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,304 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tlBitSetMask.h"
|
||||||
|
#include "tlUnitTest.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
static std::string l2s (const tl::BitSetMask &s)
|
||||||
|
{
|
||||||
|
return s.to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static tl::BitSet bs (const char *s)
|
||||||
|
{
|
||||||
|
return tl::BitSet (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(1_Basic)
|
||||||
|
{
|
||||||
|
tl::BitSetMask bs;
|
||||||
|
EXPECT_EQ (bs.is_empty (), true);
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (l2s (bs))), "");
|
||||||
|
|
||||||
|
bs.set (1, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs.size (), 2u);
|
||||||
|
EXPECT_EQ (l2s (bs), "X1");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (l2s (bs))), "X1");
|
||||||
|
|
||||||
|
bs.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "X1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (l2s (bs))), "X1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
bs.set (3, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "X1X0XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (l2s (bs))), "X1X0XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
bs.set (128, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "X1X0XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (l2s (bs))), "X1X0XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
bs.clear ();
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
|
||||||
|
bs.resize (6);
|
||||||
|
EXPECT_EQ (bs.size (), 6u);
|
||||||
|
EXPECT_EQ (l2s (bs), "XXXXXX");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(2_Equality)
|
||||||
|
{
|
||||||
|
tl::BitSetMask bs1, bs2, bs3;
|
||||||
|
|
||||||
|
EXPECT_EQ (bs1 == bs2, true);
|
||||||
|
EXPECT_EQ (bs1 != bs2, false);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 == bs2, false);
|
||||||
|
EXPECT_EQ (bs1 != bs2, true);
|
||||||
|
|
||||||
|
bs1.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 == bs2, false);
|
||||||
|
EXPECT_EQ (bs1 != bs2, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::True);
|
||||||
|
bs2.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 == bs2, true);
|
||||||
|
EXPECT_EQ (bs1 == bs3, false);
|
||||||
|
EXPECT_EQ (bs1 != bs2, false);
|
||||||
|
EXPECT_EQ (bs1 != bs3, true);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::Any);
|
||||||
|
bs1.set (32, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs1 == bs2, false);
|
||||||
|
EXPECT_EQ (bs1 == bs3, true);
|
||||||
|
EXPECT_EQ (bs1 != bs2, true);
|
||||||
|
EXPECT_EQ (bs1 != bs3, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3_Compare)
|
||||||
|
{
|
||||||
|
tl::BitSetMask bs1, bs2, bs3;
|
||||||
|
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs1.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs1 < bs3, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
EXPECT_EQ (bs3 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs1 < bs3, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
EXPECT_EQ (bs3 < bs1, true);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::Any);
|
||||||
|
bs1.set (32, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs1 < bs3, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
EXPECT_EQ (bs3 < bs1, false);
|
||||||
|
|
||||||
|
bs1.clear ();
|
||||||
|
bs2.clear ();
|
||||||
|
bs1.set (0, tl::BitSetMask::Any);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Never);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::False);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Never);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::True);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Never);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs1.set (0, tl::BitSetMask::Never);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Any);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0, tl::BitSetMask::Never);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(4_Assign)
|
||||||
|
{
|
||||||
|
tl::BitSetMask bs;
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (bs)), "");
|
||||||
|
|
||||||
|
bs.set (3, tl::BitSetMask::True);
|
||||||
|
bs.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "XXX1XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
EXPECT_EQ (tl::BitSetMask (bs).size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (tl::BitSetMask (bs)), "XXX1XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
tl::BitSetMask bs2;
|
||||||
|
bs2.swap (bs);
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (bs2.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (l2s (bs2), "XXX1XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
bs = bs2;
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "XXX1XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
bs2.clear ();
|
||||||
|
EXPECT_EQ (bs2.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs2), "");
|
||||||
|
|
||||||
|
bs2 = std::move (bs);
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (bs2.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs2), "XXX1XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
|
||||||
|
tl::BitSetMask bs3 (std::move (bs2));
|
||||||
|
EXPECT_EQ (bs2.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs2), "");
|
||||||
|
EXPECT_EQ (bs3.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs3), "XXX1XXXXXXXXXXXXXXXXXXXXXXXXXXXX0");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(5_Match)
|
||||||
|
{
|
||||||
|
tl::BitSetMask bsm;
|
||||||
|
EXPECT_EQ (bsm.match (bs ("")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("0")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("1")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("10101")), true);
|
||||||
|
|
||||||
|
bsm.set (1, tl::BitSetMask::Never);
|
||||||
|
EXPECT_EQ (l2s (bsm), "X-");
|
||||||
|
EXPECT_EQ (bsm.match (bs ("")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("0")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("1")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("10101")), false); // fails because "never bit" is used.
|
||||||
|
|
||||||
|
bsm.clear ();
|
||||||
|
bsm.set (1, tl::BitSetMask::True);
|
||||||
|
bsm.set (2, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (l2s (bsm), "X10");
|
||||||
|
|
||||||
|
EXPECT_EQ (bsm.match (bs ("")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("0")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("000")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("001")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("010")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("011")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("1")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("100")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("101")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("110")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("111")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("10101")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("11001")), true);
|
||||||
|
|
||||||
|
bsm.clear ();
|
||||||
|
bsm.set (32, tl::BitSetMask::True);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("")), false);
|
||||||
|
|
||||||
|
bsm.clear ();
|
||||||
|
bsm.set (32, tl::BitSetMask::False);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0")), true);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1")), false);
|
||||||
|
EXPECT_EQ (bsm.match (bs ("")), true); // because unset bits count as zero
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2024 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tlBitSet.h"
|
||||||
|
#include "tlUnitTest.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
static std::string l2s (const tl::BitSet &s)
|
||||||
|
{
|
||||||
|
return s.to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(1_Basic)
|
||||||
|
{
|
||||||
|
tl::BitSet bs;
|
||||||
|
EXPECT_EQ (bs.is_empty (), true);
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (l2s (bs))), "");
|
||||||
|
|
||||||
|
bs.set (1);
|
||||||
|
EXPECT_EQ (bs.size (), 2u);
|
||||||
|
EXPECT_EQ (l2s (bs), "01");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (l2s (bs))), "01");
|
||||||
|
|
||||||
|
bs.set (32);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "010000000000000000000000000000001");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (l2s (bs))), "010000000000000000000000000000001");
|
||||||
|
|
||||||
|
bs.set (3);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "010100000000000000000000000000001");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (l2s (bs))), "010100000000000000000000000000001");
|
||||||
|
|
||||||
|
unsigned int indexes[] = { 5, 6, 7 };
|
||||||
|
bs.set (indexes + 0, indexes + sizeof (indexes) / sizeof (indexes [0]));
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "010101110000000000000000000000001");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (l2s (bs))), "010101110000000000000000000000001");
|
||||||
|
|
||||||
|
bs.reset (128);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "010101110000000000000000000000001");
|
||||||
|
|
||||||
|
bs.reset (1);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "000101110000000000000000000000001");
|
||||||
|
|
||||||
|
bs.reset (indexes + 0, indexes + sizeof (indexes) / sizeof (indexes [0]));
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs.set_value (0, true);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "100100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs.set_value (indexes + 0, indexes + sizeof (indexes) / sizeof (indexes [0]), true);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "100101110000000000000000000000001");
|
||||||
|
|
||||||
|
bs.set_value (indexes + 0, indexes + sizeof (indexes) / sizeof (indexes [0]), false);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "100100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs.set_value (0, false);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs.clear ();
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
|
||||||
|
bs.resize (6);
|
||||||
|
EXPECT_EQ (bs.size (), 6u);
|
||||||
|
EXPECT_EQ (l2s (bs), "000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(2_Equality)
|
||||||
|
{
|
||||||
|
tl::BitSet bs1, bs2, bs3;
|
||||||
|
|
||||||
|
EXPECT_EQ (bs1 == bs2, true);
|
||||||
|
EXPECT_EQ (bs1 != bs2, false);
|
||||||
|
|
||||||
|
bs1.set (0);
|
||||||
|
EXPECT_EQ (bs1 == bs2, false);
|
||||||
|
EXPECT_EQ (bs1 != bs2, true);
|
||||||
|
|
||||||
|
bs1.set (32);
|
||||||
|
EXPECT_EQ (bs1 == bs2, false);
|
||||||
|
EXPECT_EQ (bs1 != bs2, true);
|
||||||
|
|
||||||
|
bs2.set (0);
|
||||||
|
bs2.set (32);
|
||||||
|
EXPECT_EQ (bs1 == bs2, true);
|
||||||
|
EXPECT_EQ (bs1 == bs3, false);
|
||||||
|
EXPECT_EQ (bs1 != bs2, false);
|
||||||
|
EXPECT_EQ (bs1 != bs3, true);
|
||||||
|
|
||||||
|
bs1.reset (0);
|
||||||
|
bs1.reset (32);
|
||||||
|
EXPECT_EQ (bs1 == bs2, false);
|
||||||
|
EXPECT_EQ (bs1 == bs3, true);
|
||||||
|
EXPECT_EQ (bs1 != bs2, true);
|
||||||
|
EXPECT_EQ (bs1 != bs3, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3_Compare)
|
||||||
|
{
|
||||||
|
tl::BitSet bs1, bs2, bs3;
|
||||||
|
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
|
||||||
|
bs1.set (0);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs1.set (32);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, true);
|
||||||
|
|
||||||
|
bs2.set (0);
|
||||||
|
bs2.set (32);
|
||||||
|
EXPECT_EQ (bs1 < bs2, false);
|
||||||
|
EXPECT_EQ (bs1 < bs3, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
EXPECT_EQ (bs3 < bs1, true);
|
||||||
|
|
||||||
|
bs1.reset (0);
|
||||||
|
bs1.reset (32);
|
||||||
|
EXPECT_EQ (bs1 < bs2, true);
|
||||||
|
EXPECT_EQ (bs1 < bs3, false);
|
||||||
|
EXPECT_EQ (bs2 < bs1, false);
|
||||||
|
EXPECT_EQ (bs3 < bs1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(4_Assign)
|
||||||
|
{
|
||||||
|
tl::BitSet bs;
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (bs)), "");
|
||||||
|
|
||||||
|
bs.set (3);
|
||||||
|
bs.set (32);
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "000100000000000000000000000000001");
|
||||||
|
EXPECT_EQ (tl::BitSet (bs).size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (tl::BitSet (bs)), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
tl::BitSet bs2;
|
||||||
|
bs2.swap (bs);
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (bs2.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (l2s (bs2), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs = bs2;
|
||||||
|
EXPECT_EQ (bs.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs2.clear ();
|
||||||
|
EXPECT_EQ (bs2.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs2), "");
|
||||||
|
|
||||||
|
bs2 = std::move (bs);
|
||||||
|
EXPECT_EQ (bs.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs), "");
|
||||||
|
EXPECT_EQ (bs2.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs2), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
tl::BitSet bs3 (std::move (bs2));
|
||||||
|
EXPECT_EQ (bs2.size (), 0u);
|
||||||
|
EXPECT_EQ (l2s (bs2), "");
|
||||||
|
EXPECT_EQ (bs3.size (), 33u);
|
||||||
|
EXPECT_EQ (l2s (bs3), "000100000000000000000000000000001");
|
||||||
|
|
||||||
|
bs.clear ();
|
||||||
|
|
||||||
|
unsigned int indexes[] = { 5, 6, 7 };
|
||||||
|
bs = std::move (tl::BitSet (indexes + 0, indexes + sizeof (indexes) / sizeof (indexes [0])));
|
||||||
|
EXPECT_EQ (bs.size (), 8u);
|
||||||
|
EXPECT_EQ (l2s (bs), "00000111");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,9 @@ include($$PWD/../../lib_ut.pri)
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
tlAlgorithmTests.cc \
|
tlAlgorithmTests.cc \
|
||||||
tlBase64Tests.cc \
|
tlBase64Tests.cc \
|
||||||
|
tlBitSetMapTests.cc \
|
||||||
|
tlBitSetMaskTests.cc \
|
||||||
|
tlBitSetTests.cc \
|
||||||
tlClassRegistryTests.cc \
|
tlClassRegistryTests.cc \
|
||||||
tlCommandLineParserTests.cc \
|
tlCommandLineParserTests.cc \
|
||||||
tlColorTests.cc \
|
tlColorTests.cc \
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue