WIP: Fixed PCB import for non-Qt builds, added missing file.

This commit is contained in:
Matthias Koefferlein 2018-07-08 23:44:36 +02:00
parent 221d5a4a38
commit 260243a6d9
14 changed files with 1389 additions and 721 deletions

View File

@ -119,6 +119,7 @@ SOURCES = \
gsiDeclDbVector.cc \
gsiDeclDbLayoutDiff.cc \
gsiDeclDbGlyphs.cc \
dbConverters.cc
HEADERS = \
dbArray.h \
@ -206,7 +207,8 @@ HEADERS = \
dbNamedLayerReader.h \
dbForceLink.h \
dbPlugin.h \
dbInit.h
dbInit.h \
dbConverters.h
!equals(HAVE_QT, "0") {

32
src/db/db/dbConverters.cc Normal file
View File

@ -0,0 +1,32 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbConverters.h"
#include "tlInternational.h"
namespace db
{
// .. nothing yet ..
}

101
src/db/db/dbConverters.h Normal file
View File

@ -0,0 +1,101 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_dbConverters
#define HDR_dbConverters
#include "dbCommon.h"
#include "dbLayerProperties.h"
#include "dbTrans.h"
#include "dbPoint.h"
namespace db
{
/**
* @brief A converter for transformations
*
* T is supposed a transformation type such as "db::DCplxTrans".
*/
template <class T>
struct DB_PUBLIC TransformationConverter
{
std::string to_string (const T &t) const
{
return t.to_string ();
}
void from_string (const std::string &s, T &t) const
{
tl::Extractor ex (s.c_str ());
ex.read (t);
ex.expect_end ();
}
};
/**
* @brief A converter for layout layers
*/
struct DB_PUBLIC LayoutLayerConverter
{
std::string to_string (const db::LayerProperties &p) const
{
return p.to_string ();
}
void from_string (const std::string &s, db::LayerProperties &p) const
{
tl::Extractor ex (s.c_str ());
p.read (ex);
ex.expect_end ();
}
};
/**
* @brief A converter for points
*
* P is supposed to be a point type (i.e. db::DPoint).
*/
template <class P>
struct DB_PUBLIC PointConverter
{
std::string to_string (const P &p) const
{
return tl::to_string (p.x ()) + "," + tl::to_string (p.y ());
}
void from_string (const std::string &s, P &p) const
{
typename P::coord_type x, y;
tl::Extractor ex (s.c_str ());
ex.read (x);
ex.expect (",");
ex.read (y);
p = P (x, y);
ex.expect_end ();
}
};
}
#endif

View File

@ -28,8 +28,6 @@
#include <QColor>
#include "dbLayerProperties.h"
namespace lay
{
@ -42,70 +40,6 @@ struct LAYBASIC_PUBLIC ColorConverter
void from_string (const std::string &s, QColor &c) const;
};
/**
* @brief A converter for transformations
*
* T is supposed a transformation type such as "db::DCplxTrans".
*/
template <class T>
struct LAYBASIC_PUBLIC TransformationConverter
{
std::string to_string (const T &t) const
{
return t.to_string ();
}
void from_string (const std::string &s, T &t) const
{
tl::Extractor ex (s.c_str ());
ex.read (t);
ex.expect_end ();
}
};
/**
* @brief A converter for layout layers
*/
struct LAYBASIC_PUBLIC LayoutLayerConverter
{
std::string to_string (const db::LayerProperties &p) const
{
return p.to_string ();
}
void from_string (const std::string &s, db::LayerProperties &p) const
{
tl::Extractor ex (s.c_str ());
p.read (ex);
ex.expect_end ();
}
};
/**
* @brief A converter for points
*
* P is supposed to be a point type (i.e. db::DPoint).
*/
template <class P>
struct LAYBASIC_PUBLIC PointConverter
{
std::string to_string (const P &p) const
{
return tl::to_string (p.x ()) + "," + tl::to_string (p.y ());
}
void from_string (const std::string &s, P &p) const
{
typename P::coord_type x, y;
tl::Extractor ex (s.c_str ());
ex.read (x);
ex.expect (",");
ex.read (y);
p = P (x, y);
ex.expect_end ();
}
};
}
#endif

View File

@ -0,0 +1,517 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbGerberImportData.h"
#include "dbGerberImporter.h"
#include "dbPoint.h"
#include "dbConverters.h"
#include "tlFileUtils.h"
#include "tlXMLParser.h"
namespace db
{
// -----------------------------------------------------------------------------------------
// GerberImportData implementation
GerberImportData::GerberImportData ()
: invert_negative_layers (false), border (5000),
free_layer_mapping (false), mode (ModeSamePanel), mounting (MountingTop),
num_metal_layers (0), num_via_types (0), num_circle_points (-1),
merge_flag (false), dbu (0.001), topcell_name ("PCB")
{
// .. nothing yet ..
}
void
GerberImportData::reset ()
{
double dbu_saved = dbu;
std::string base_dir_saved = base_dir;
bool free_layer_mapping_saved = free_layer_mapping;
mode_type mode_saved = mode;
*this = GerberImportData ();
dbu = dbu_saved;
base_dir = base_dir_saved;
free_layer_mapping = free_layer_mapping_saved;
mode = mode_saved;
}
std::string
GerberImportData::get_layer_properties_file () const
{
std::string lyp_file = layer_properties_file;
if (! lyp_file.empty ()) {
if (! base_dir.empty () && ! tl::is_absolute (lyp_file)) {
lyp_file = tl::absolute_file_path (tl::combine_path (base_dir, lyp_file));
}
}
return lyp_file;
}
void
GerberImportData::setup_importer (db::GerberImporter *importer)
{
if (num_circle_points >= 4) {
importer->set_circle_points (num_circle_points);
}
importer->set_dbu (dbu);
importer->set_cell_name (topcell_name);
importer->set_dir (base_dir);
importer->set_global_trans (explicit_trans);
importer->set_reference_points (reference_points);
importer->set_merge (merge_flag);
importer->set_invert_negative_layers (invert_negative_layers);
importer->set_border (border);
if (free_layer_mapping) {
for (std::vector<GerberFreeFileDescriptor>::iterator file = free_files.begin (); file != free_files.end (); ++file) {
if (! file->filename.empty ()) {
db::GerberFile file_spec;
file_spec.set_filename (file->filename);
for (std::vector <int>::const_iterator i = file->layout_layers.begin (); i != file->layout_layers.end (); ++i) {
if (*i >= 0 && *i < int (layout_layers.size ())) {
file_spec.add_layer_spec (layout_layers [*i]);
}
}
importer->add_file (file_spec);
}
}
} else {
for (std::vector<GerberArtworkFileDescriptor>::iterator file = artwork_files.begin (); file != artwork_files.end (); ++file) {
if (! file->filename.empty ()) {
size_t n;
if (mounting == MountingTop) {
n = std::distance (artwork_files.begin (), file);
} else {
n = std::distance (file, artwork_files.end ()) - 1;
}
if (n * 2 < layout_layers.size ()) {
db::GerberFile file_spec;
file_spec.set_filename (file->filename);
file_spec.add_layer_spec (layout_layers [n * 2]);
importer->add_file (file_spec);
}
}
}
for (std::vector<GerberDrillFileDescriptor>::iterator file = drill_files.begin (); file != drill_files.end (); ++file) {
if (! file->filename.empty ()) {
size_t nstart, nstop;
if (mounting == MountingTop) {
nstart = std::distance (artwork_files.begin (), artwork_files.begin () + file->start);
nstop = std::distance (artwork_files.begin (), artwork_files.begin () + file->stop);
} else {
nstop = std::distance (artwork_files.begin () + file->start, artwork_files.end ()) - 1;
nstart = std::distance (artwork_files.begin () + file->stop, artwork_files.end ()) - 1;
}
db::GerberFile file_spec;
file_spec.set_filename (file->filename);
for (size_t n = nstart; n < nstop; ++n) {
if (n * 2 + 1 < layout_layers.size ()) {
file_spec.add_layer_spec (layout_layers [n * 2 + 1]);
}
}
importer->add_file (file_spec);
}
}
}
}
struct MountingConverter
{
std::string to_string (GerberImportData::mounting_type m) const
{
return m == GerberImportData::MountingTop ? "top" : "bottom";
}
void from_string (const std::string &s, GerberImportData::mounting_type &m) const
{
if (s == "top") {
m = GerberImportData::MountingTop;
} else if (s == "bottom") {
m = GerberImportData::MountingBottom;
} else {
throw tl::Exception (tl::to_string (tr ("Invalid mounting specification: %s")), s);
}
}
};
// declaration of the layer properties file XML structure
static const tl::XMLStruct <GerberImportData>
pcb_project_structure ("pcb-project",
tl::make_member (&GerberImportData::invert_negative_layers, "invert-negative-layers") +
tl::make_member (&GerberImportData::border, "border") +
tl::make_member (&GerberImportData::free_layer_mapping, "free-layer-mapping") +
tl::make_element (&GerberImportData::layout_layers, "layout-layers",
tl::make_member<db::LayerProperties, std::vector<db::LayerProperties>::const_iterator, std::vector<db::LayerProperties> > (&std::vector<db::LayerProperties>::begin, &std::vector<db::LayerProperties>::end, &std::vector<db::LayerProperties>::push_back, "layout-layer", db::LayoutLayerConverter ())
) +
tl::make_member (&GerberImportData::mounting, "mounting", MountingConverter ()) +
tl::make_member (&GerberImportData::num_metal_layers, "num-metal-layers") +
tl::make_member (&GerberImportData::num_via_types, "num-via-types") +
tl::make_element (&GerberImportData::artwork_files, "artwork-files",
tl::make_element<GerberArtworkFileDescriptor, std::vector<GerberArtworkFileDescriptor>::const_iterator, std::vector<GerberArtworkFileDescriptor> > (&std::vector<GerberArtworkFileDescriptor>::begin, &std::vector<GerberArtworkFileDescriptor>::end, &std::vector<GerberArtworkFileDescriptor>::push_back, "artwork-file",
tl::make_member (&GerberArtworkFileDescriptor::filename, "filename")
)
) +
tl::make_element (&GerberImportData::drill_files, "drill-files",
tl::make_element<GerberDrillFileDescriptor, std::vector<GerberDrillFileDescriptor>::const_iterator, std::vector<GerberDrillFileDescriptor> > (&std::vector<GerberDrillFileDescriptor>::begin, &std::vector<GerberDrillFileDescriptor>::end, &std::vector<GerberDrillFileDescriptor>::push_back, "drill-file",
tl::make_member (&GerberDrillFileDescriptor::start, "start") +
tl::make_member (&GerberDrillFileDescriptor::stop, "stop") +
tl::make_member (&GerberDrillFileDescriptor::filename, "filename")
)
) +
tl::make_element (&GerberImportData::free_files, "free-files",
tl::make_element<GerberFreeFileDescriptor, std::vector<GerberFreeFileDescriptor>::const_iterator, std::vector<GerberFreeFileDescriptor> > (&std::vector<GerberFreeFileDescriptor>::begin, &std::vector<GerberFreeFileDescriptor>::end, &std::vector<GerberFreeFileDescriptor>::push_back, "free-file",
tl::make_member (&GerberFreeFileDescriptor::filename, "filename") +
tl::make_element (&GerberFreeFileDescriptor::layout_layers, "layout-layers",
tl::make_member<int, std::vector<int>::const_iterator, std::vector<int> > (&std::vector<int>::begin, &std::vector<int>::end, &std::vector<int>::push_back, "index")
)
)
) +
tl::make_element (&GerberImportData::reference_points, "reference-points",
tl::make_element<std::pair <db::DPoint, db::DPoint>, std::vector<std::pair <db::DPoint, db::DPoint> >::const_iterator, std::vector<std::pair <db::DPoint, db::DPoint> > > (&std::vector<std::pair <db::DPoint, db::DPoint> >::begin, &std::vector<std::pair <db::DPoint, db::DPoint> >::end, &std::vector<std::pair <db::DPoint, db::DPoint> >::push_back, "reference-point",
tl::make_member (&std::pair <db::DPoint, db::DPoint>::first, "pcb", db::PointConverter<db::DPoint> ()) +
tl::make_member (&std::pair <db::DPoint, db::DPoint>::second, "layout", db::PointConverter<db::DPoint> ())
)
) +
tl::make_member (&GerberImportData::explicit_trans, "explicit-trans", db::TransformationConverter<db::DCplxTrans> ()) +
tl::make_member (&GerberImportData::layer_properties_file, "layer-properties-file") +
tl::make_member (&GerberImportData::num_circle_points, "num-circle-points") +
tl::make_member (&GerberImportData::merge_flag, "merge-flag") +
tl::make_member (&GerberImportData::dbu, "dbu") +
tl::make_member (&GerberImportData::topcell_name, "cell-name")
);
void
GerberImportData::load (const std::string &file)
{
reset ();
current_file = file;
tl::XMLFileSource in (file);
pcb_project_structure.parse (in, *this);
}
void
GerberImportData::load (tl::InputStream &stream)
{
reset ();
current_file = std::string ();
tl::XMLStreamSource in (stream);
pcb_project_structure.parse (in, *this);
}
void
GerberImportData::save (const std::string &file)
{
tl::OutputStream os (file, tl::OutputStream::OM_Plain);
pcb_project_structure.write (os, *this);
current_file = file;
}
void
GerberImportData::from_string (const std::string &s)
{
tl::Extractor ex (s.c_str ());
while (! ex.at_end ()) {
if (ex.test ("free-layer-mapping")) {
ex.test ("=");
ex.read (free_layer_mapping);
ex.test (";");
} else if (ex.test ("invert-negative-layers")) {
ex.test ("=");
ex.read (invert_negative_layers);
ex.test (";");
} else if (ex.test ("border")) {
ex.test ("=");
ex.read (border);
ex.test (";");
} else if (ex.test ("import-mode")) {
ex.test ("=");
int m = 0;
ex.read (m);
mode = (mode_type) m;
ex.test (";");
} else if (ex.test ("base-dir")) {
ex.test ("=");
ex.read_word_or_quoted (base_dir);
ex.test (";");
} else if (ex.test ("layout-layers")) {
ex.test ("=");
layout_layers.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
layout_layers.push_back (db::LayerProperties ());
layout_layers.back ().read (ex);
ex.test (",");
}
ex.test (";");
} else if (ex.test ("mounting")) {
ex.test ("=");
std::string m;
ex.read_word (m);
mounting = (m == "top") ? MountingTop : MountingBottom;
ex.test (";");
} else if (ex.test ("num-metal-layers")) {
ex.test ("=");
ex.read (num_metal_layers);
ex.test (";");
} else if (ex.test ("num-via-types")) {
ex.test ("=");
ex.read (num_via_types);
ex.test (";");
} else if (ex.test ("artwork-files")) {
ex.test ("=");
artwork_files.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
ex.test ("(");
artwork_files.push_back (db::GerberArtworkFileDescriptor ());
ex.read_word_or_quoted (artwork_files.back ().filename);
ex.test (")");
ex.test (",");
}
ex.test (";");
} else if (ex.test ("drill-files")) {
ex.test ("=");
drill_files.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
ex.test ("(");
drill_files.push_back (db::GerberDrillFileDescriptor ());
ex.read (drill_files.back ().start);
ex.test (",");
ex.read (drill_files.back ().stop);
ex.test (",");
ex.read_word_or_quoted (drill_files.back ().filename);
ex.test (")");
ex.test (",");
}
ex.test (";");
} else if (ex.test ("free-files")) {
ex.test ("=");
free_files.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
ex.test ("(");
free_files.push_back (db::GerberFreeFileDescriptor ());
ex.read_word_or_quoted (free_files.back ().filename);
ex.test (",");
while (! ex.test (")") && ! ex.at_end ()) {
int i = -1;
ex.read (i);
free_files.back ().layout_layers.push_back (i);
ex.test (",");
}
ex.test (",");
}
ex.test (";");
} else if (ex.test ("reference-points")) {
ex.test ("=");
reference_points.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
double x1, y1, x2, y2;
ex.test ("(");
ex.test ("(");
ex.read (x1);
ex.test (",");
ex.read (y1);
ex.test (")");
ex.test (",");
ex.test ("(");
ex.read (x2);
ex.test (",");
ex.read (y2);
ex.test (")");
ex.test (")");
ex.test (",");
reference_points.push_back (std::make_pair (db::DPoint (x1, y1), db::DPoint (x2, y2)));
}
ex.test (";");
} else if (ex.test ("explicit-trans")) {
ex.test ("=");
ex.read (explicit_trans);
ex.test (";");
} else if (ex.test ("layer-properties-file")) {
ex.test ("=");
ex.read_word_or_quoted (layer_properties_file);
ex.test (";");
} else if (ex.test ("num-circle-points")) {
ex.test ("=");
ex.read (num_circle_points);
ex.test (";");
} else if (ex.test ("merge-flag")) {
ex.test ("=");
ex.read (merge_flag);
ex.test (";");
} else if (ex.test ("dbu")) {
ex.test ("=");
ex.read (dbu);
ex.test (";");
} else if (ex.test ("cell-name")) {
ex.test ("=");
ex.read_word_or_quoted (topcell_name);
ex.test (";");
} else {
ex.expect_end ();
}
}
}
std::string
GerberImportData::to_string () const
{
std::string s;
s += "free-layer-mapping=" + tl::to_string(free_layer_mapping) + ";";
s += "import-mode=" + tl::to_string(int (mode)) + ";";
s += "base-dir=" + tl::to_quoted_string (base_dir) + ";";
s += "invert-negative-layers=" + tl::to_string (invert_negative_layers) + ";";
s += "border=" + tl::to_string (border) + ";";
s += "layout-layers=";
for (std::vector <db::LayerProperties>::const_iterator ll = layout_layers.begin (); ll != layout_layers.end (); ++ll) {
if (ll != layout_layers.begin ()) {
s += ",";
}
s += ll->to_string ();
}
s += ";";
s += "mounting=" + std::string (mounting == MountingTop ? "top" : "bottom") + ";";
s += "num-metal-layers=" + tl::to_string (num_metal_layers) + ";";
s += "num-via-types=" + tl::to_string (num_via_types) + ";";
s += "artwork-files=";
for (std::vector <GerberArtworkFileDescriptor>::const_iterator f = artwork_files.begin (); f != artwork_files.end (); ++f) {
if (f != artwork_files.begin ()) {
s += ",";
}
s += "(" + tl::to_quoted_string (f->filename) + ")";
}
s += ";";
s += "drill-files=";
for (std::vector <GerberDrillFileDescriptor>::const_iterator f = drill_files.begin (); f != drill_files.end (); ++f) {
if (f != drill_files.begin ()) {
s += ",";
}
s += "(" + tl::to_string (f->start) + "," + tl::to_string (f->stop) + "," + tl::to_quoted_string (f->filename) + ")";
}
s += ";";
s += "free-files=";
for (std::vector <GerberFreeFileDescriptor>::const_iterator f = free_files.begin (); f != free_files.end (); ++f) {
if (f != free_files.begin ()) {
s += ",";
}
s += "(" + tl::to_quoted_string (f->filename);
for (std::vector <int>::const_iterator i = f->layout_layers.begin (); i != f->layout_layers.end (); ++i) {
s += "," + tl::to_string (*i);
}
s += ")";
}
s += ";";
s += "reference-points=";
for (std::vector <std::pair <db::DPoint, db::DPoint> >::const_iterator rp = reference_points.begin (); rp != reference_points.end (); ++rp) {
if (rp != reference_points.begin ()) {
s += ",";
}
s += "((" + tl::to_string (rp->first.x ()) + "," + tl::to_string (rp->first.y ()) + "),("
+ tl::to_string (rp->second.x ()) + "," + tl::to_string (rp->second.y ()) + "))";
}
s += ";";
s += "explicit-trans=" + explicit_trans.to_string () + ";";
s += "layer-properties-file=" + tl::to_quoted_string (layer_properties_file) + ";";
s += "num-circle-points=" + tl::to_string (num_circle_points) + ";";
s += "merge-flag=" + tl::to_string (merge_flag) + ";";
s += "dbu=" + tl::to_string (dbu) + ";";
s += "cell-name=" + tl::to_quoted_string (topcell_name) + ";";
return s;
}
}

View File

@ -0,0 +1,102 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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_dbGerberImportData
#define HDR_dbGerberImportData
#include "dbTrans.h"
#include "dbLayerProperties.h"
#include "tlStream.h"
#include <string>
#include <vector>
namespace db
{
class GerberImporter;
struct GerberArtworkFileDescriptor
{
std::string filename;
};
struct GerberDrillFileDescriptor
{
GerberDrillFileDescriptor () : start (-1), stop (-1) { }
int start;
int stop;
std::string filename;
};
struct GerberFreeFileDescriptor
{
std::string filename;
std::vector<int> layout_layers;
};
struct GerberImportData
{
public:
GerberImportData ();
enum mode_type { ModeIntoLayout = 0, ModeSamePanel, ModeNewPanel };
enum mounting_type { MountingTop = 0, MountingBottom };
bool invert_negative_layers;
double border;
bool free_layer_mapping;
mode_type mode;
std::string base_dir;
std::string current_file;
std::vector <db::LayerProperties> layout_layers;
mounting_type mounting;
int num_metal_layers;
int num_via_types;
std::vector <GerberArtworkFileDescriptor> artwork_files;
std::vector <GerberDrillFileDescriptor> drill_files;
std::vector <GerberFreeFileDescriptor> free_files;
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
db::DCplxTrans explicit_trans;
std::string layer_properties_file;
int num_circle_points;
bool merge_flag;
double dbu;
std::string topcell_name;
std::string get_layer_properties_file () const;
void setup_importer (db::GerberImporter *importer);
void reset ();
void load (tl::InputStream &stream);
void load (const std::string &file);
void save (const std::string &file);
void from_string (const std::string &s);
std::string to_string () const;
};
}
#endif

View File

@ -22,8 +22,12 @@
#include "dbGerberImporter.h"
#include "dbGerberImportData.h"
#include "dbGerberDrillFileReader.h"
#include "dbRS274XReader.h"
#include "dbReader.h"
#include "dbStream.h"
#include "tlStream.h"
#include "tlString.h"
#include "tlString.h"
@ -1070,5 +1074,111 @@ GerberImporter::do_read (db::Layout &layout, db::cell_index_type cell_index)
}
// ---------------------------------------------------------------
// Plugin for the stream reader
class GerberReader
: public db::ReaderBase
{
public:
GerberReader (tl::InputStream &s)
: m_stream (s)
{
// .. nothing yet ..
}
~GerberReader ()
{
// .. nothing yet ..
}
virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions & /*options*/) throw (tl::Exception)
{
// TODO: too simple, should provide at least a layer filtering.
return read (layout);
}
virtual const db::LayerMap &read (db::Layout &layout) throw (tl::Exception)
{
db::GerberImportData data;
std::string fn (m_stream.source ());
if (! fn.empty ()) {
data.base_dir = tl::absolute_path (fn);
}
data.load (m_stream);
db::GerberImporter importer;
data.setup_importer (&importer);
importer.read (layout);
std::string lyr_file = data.get_layer_properties_file ();
if (! lyr_file.empty ()) {
layout.add_meta_info (db::MetaInfo ("layer-properties-file", "Layer Properties File", lyr_file));
}
return m_layers;
}
virtual const char *format () const
{
return "GerberPCB";
}
private:
tl::InputStream &m_stream;
db::LayerMap m_layers;
};
class GerberFormatDeclaration
: public db::StreamFormatDeclaration
{
virtual std::string format_name () const { return "GerberPCB"; }
virtual std::string format_desc () const { return "Gerber PCB"; }
virtual std::string format_title () const { return "Gerber PCB (project files)"; }
virtual std::string file_format () const { return "Gerber PCB project files (*.pcb)"; }
virtual bool detect (tl::InputStream &stream) const
{
// The test is that somewhere within the first 1000 bytes, a <pcb-project> XML tag appears.
// 1000 bytes are within the initial block that the stream reader reads and hence
// this does not trigger any reread which is not available on some sources.
// TODO: this is pretty simple test. A more elaborate test would be in place here.
std::string h = stream.read_all (1000);
// HINT: this assumes UTF8 or ISO encoding ...
if (h.find ("<pcb-project>") != std::string::npos) {
return true;
} else {
return false;
}
}
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
{
return new GerberReader (s);
}
virtual db::WriterBase *create_writer () const
{
return 0;
}
virtual bool can_read () const
{
return true;
}
virtual bool can_write () const
{
return false;
}
};
static tl::RegisteredClass<db::StreamFormatDeclaration> format_decl (new GerberFormatDeclaration (), 1000, "GerberPCB");
}

View File

@ -8,10 +8,12 @@ HEADERS = \
dbGerberDrillFileReader.h \
dbGerberImporter.h \
dbRS274XApertures.h \
dbRS274XReader.h
dbRS274XReader.h \
dbGerberImportData.h
SOURCES = \
dbGerberDrillFileReader.cc \
dbGerberImporter.cc \
dbRS274XApertures.cc \
dbRS274XReader.cc
dbRS274XReader.cc \
dbGerberImportData.cc

View File

@ -191,113 +191,5 @@ private:
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new lay::GerberImportPluginDeclaration (), 1200, "db::GerberImportPlugin");
// ---------------------------------------------------------------
// Plugin for the stream reader
class GerberReader
: public db::ReaderBase
{
public:
GerberReader (tl::InputStream &s)
: m_stream (s)
{
// .. nothing yet ..
}
~GerberReader ()
{
// .. nothing yet ..
}
virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions & /*options*/) throw (tl::Exception)
{
// TODO: too simple, should provide at least a layer filtering.
return read (layout);
}
virtual const db::LayerMap &read (db::Layout &layout) throw (tl::Exception)
{
GerberImportData data;
std::string fn (m_stream.source ());
if (! fn.empty ()) {
QFileInfo fi (tl::to_qstring (fn));
data.base_dir = tl::to_string (fi.absoluteDir ().path ());
}
data.load (m_stream);
db::GerberImporter importer;
data.setup_importer (&importer);
importer.read (layout);
std::string lyr_file = data.get_layer_properties_file ();
if (! lyr_file.empty ()) {
layout.add_meta_info (db::MetaInfo ("layer-properties-file", "Layer Properties File", lyr_file));
}
return m_layers;
}
virtual const char *format () const
{
return "GerberPCB";
}
private:
tl::InputStream &m_stream;
db::LayerMap m_layers;
};
class GerberFormatDeclaration
: public db::StreamFormatDeclaration
{
virtual std::string format_name () const { return "GerberPCB"; }
virtual std::string format_desc () const { return "Gerber PCB"; }
virtual std::string format_title () const { return "Gerber PCB (project files)"; }
virtual std::string file_format () const { return "Gerber PCB project files (*.pcb)"; }
virtual bool detect (tl::InputStream &stream) const
{
// The test is that somewhere within the first 1000 bytes, a <pcb-project> XML tag appears.
// 1000 bytes are within the initial block that the stream reader reads and hence
// this does not trigger any reread which is not available on some sources.
// TODO: this is pretty simple test. A more elaborate test would be in place here.
std::string h = stream.read_all (1000);
// HINT: this assumes UTF8 or ISO encoding ...
if (h.find ("<pcb-project>") != std::string::npos) {
return true;
} else {
return false;
}
}
virtual db::ReaderBase *create_reader (tl::InputStream &s) const
{
return new GerberReader (s);
}
virtual db::WriterBase *create_writer () const
{
return 0;
}
virtual bool can_read () const
{
return true;
}
virtual bool can_write () const
{
return false;
}
};
static tl::RegisteredClass<db::StreamFormatDeclaration> format_decl (new GerberFormatDeclaration (), 1000, "GerberPCB");
}

View File

@ -42,491 +42,6 @@
namespace lay
{
// -----------------------------------------------------------------------------------------
// GerberImportData implementation
GerberImportData::GerberImportData ()
: invert_negative_layers (false), border (5000),
free_layer_mapping (false), mode (ModeSamePanel), mounting (MountingTop),
num_metal_layers (0), num_via_types (0), num_circle_points (-1),
merge_flag (false), dbu (0.001), topcell_name ("PCB")
{
// .. nothing yet ..
}
void
GerberImportData::reset ()
{
double dbu_saved = dbu;
std::string base_dir_saved = base_dir;
bool free_layer_mapping_saved = free_layer_mapping;
mode_type mode_saved = mode;
*this = GerberImportData ();
dbu = dbu_saved;
base_dir = base_dir_saved;
free_layer_mapping = free_layer_mapping_saved;
mode = mode_saved;
}
std::string
GerberImportData::get_layer_properties_file () const
{
std::string lyp_file = layer_properties_file;
if (! lyp_file.empty ()) {
QFileInfo lyp_file_info (tl::to_qstring (lyp_file));
if (! base_dir.empty () && ! lyp_file_info.isAbsolute ()) {
lyp_file_info = QFileInfo (QDir (tl::to_qstring (base_dir)), tl::to_qstring (lyp_file));
lyp_file = tl::to_string (lyp_file_info.absoluteFilePath ());
}
}
return lyp_file;
}
void
GerberImportData::setup_importer (db::GerberImporter *importer)
{
if (num_circle_points >= 4) {
importer->set_circle_points (num_circle_points);
}
importer->set_dbu (dbu);
importer->set_cell_name (topcell_name);
importer->set_dir (base_dir);
importer->set_global_trans (explicit_trans);
importer->set_reference_points (reference_points);
importer->set_merge (merge_flag);
importer->set_invert_negative_layers (invert_negative_layers);
importer->set_border (border);
if (free_layer_mapping) {
for (std::vector<GerberFreeFileDescriptor>::iterator file = free_files.begin (); file != free_files.end (); ++file) {
if (! file->filename.empty ()) {
db::GerberFile file_spec;
file_spec.set_filename (file->filename);
for (std::vector <int>::const_iterator i = file->layout_layers.begin (); i != file->layout_layers.end (); ++i) {
if (*i >= 0 && *i < int (layout_layers.size ())) {
file_spec.add_layer_spec (layout_layers [*i]);
}
}
importer->add_file (file_spec);
}
}
} else {
for (std::vector<GerberArtworkFileDescriptor>::iterator file = artwork_files.begin (); file != artwork_files.end (); ++file) {
if (! file->filename.empty ()) {
size_t n;
if (mounting == MountingTop) {
n = std::distance (artwork_files.begin (), file);
} else {
n = std::distance (file, artwork_files.end ()) - 1;
}
if (n * 2 < layout_layers.size ()) {
db::GerberFile file_spec;
file_spec.set_filename (file->filename);
file_spec.add_layer_spec (layout_layers [n * 2]);
importer->add_file (file_spec);
}
}
}
for (std::vector<GerberDrillFileDescriptor>::iterator file = drill_files.begin (); file != drill_files.end (); ++file) {
if (! file->filename.empty ()) {
size_t nstart, nstop;
if (mounting == MountingTop) {
nstart = std::distance (artwork_files.begin (), artwork_files.begin () + file->start);
nstop = std::distance (artwork_files.begin (), artwork_files.begin () + file->stop);
} else {
nstop = std::distance (artwork_files.begin () + file->start, artwork_files.end ()) - 1;
nstart = std::distance (artwork_files.begin () + file->stop, artwork_files.end ()) - 1;
}
db::GerberFile file_spec;
file_spec.set_filename (file->filename);
for (size_t n = nstart; n < nstop; ++n) {
if (n * 2 + 1 < layout_layers.size ()) {
file_spec.add_layer_spec (layout_layers [n * 2 + 1]);
}
}
importer->add_file (file_spec);
}
}
}
}
struct MountingConverter
{
std::string to_string (GerberImportData::mounting_type m) const
{
return m == GerberImportData::MountingTop ? "top" : "bottom";
}
void from_string (const std::string &s, GerberImportData::mounting_type &m) const
{
if (s == "top") {
m = GerberImportData::MountingTop;
} else if (s == "bottom") {
m = GerberImportData::MountingBottom;
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Invalid mounting specification: %s")), s);
}
}
};
// declaration of the layer properties file XML structure
static const tl::XMLStruct <GerberImportData>
pcb_project_structure ("pcb-project",
tl::make_member (&GerberImportData::invert_negative_layers, "invert-negative-layers") +
tl::make_member (&GerberImportData::border, "border") +
tl::make_member (&GerberImportData::free_layer_mapping, "free-layer-mapping") +
tl::make_element (&GerberImportData::layout_layers, "layout-layers",
tl::make_member<db::LayerProperties, std::vector<db::LayerProperties>::const_iterator, std::vector<db::LayerProperties> > (&std::vector<db::LayerProperties>::begin, &std::vector<db::LayerProperties>::end, &std::vector<db::LayerProperties>::push_back, "layout-layer", lay::LayoutLayerConverter ())
) +
tl::make_member (&GerberImportData::mounting, "mounting", MountingConverter ()) +
tl::make_member (&GerberImportData::num_metal_layers, "num-metal-layers") +
tl::make_member (&GerberImportData::num_via_types, "num-via-types") +
tl::make_element (&GerberImportData::artwork_files, "artwork-files",
tl::make_element<GerberArtworkFileDescriptor, std::vector<GerberArtworkFileDescriptor>::const_iterator, std::vector<GerberArtworkFileDescriptor> > (&std::vector<GerberArtworkFileDescriptor>::begin, &std::vector<GerberArtworkFileDescriptor>::end, &std::vector<GerberArtworkFileDescriptor>::push_back, "artwork-file",
tl::make_member (&GerberArtworkFileDescriptor::filename, "filename")
)
) +
tl::make_element (&GerberImportData::drill_files, "drill-files",
tl::make_element<GerberDrillFileDescriptor, std::vector<GerberDrillFileDescriptor>::const_iterator, std::vector<GerberDrillFileDescriptor> > (&std::vector<GerberDrillFileDescriptor>::begin, &std::vector<GerberDrillFileDescriptor>::end, &std::vector<GerberDrillFileDescriptor>::push_back, "drill-file",
tl::make_member (&GerberDrillFileDescriptor::start, "start") +
tl::make_member (&GerberDrillFileDescriptor::stop, "stop") +
tl::make_member (&GerberDrillFileDescriptor::filename, "filename")
)
) +
tl::make_element (&GerberImportData::free_files, "free-files",
tl::make_element<GerberFreeFileDescriptor, std::vector<GerberFreeFileDescriptor>::const_iterator, std::vector<GerberFreeFileDescriptor> > (&std::vector<GerberFreeFileDescriptor>::begin, &std::vector<GerberFreeFileDescriptor>::end, &std::vector<GerberFreeFileDescriptor>::push_back, "free-file",
tl::make_member (&GerberFreeFileDescriptor::filename, "filename") +
tl::make_element (&GerberFreeFileDescriptor::layout_layers, "layout-layers",
tl::make_member<int, std::vector<int>::const_iterator, std::vector<int> > (&std::vector<int>::begin, &std::vector<int>::end, &std::vector<int>::push_back, "index")
)
)
) +
tl::make_element (&GerberImportData::reference_points, "reference-points",
tl::make_element<std::pair <db::DPoint, db::DPoint>, std::vector<std::pair <db::DPoint, db::DPoint> >::const_iterator, std::vector<std::pair <db::DPoint, db::DPoint> > > (&std::vector<std::pair <db::DPoint, db::DPoint> >::begin, &std::vector<std::pair <db::DPoint, db::DPoint> >::end, &std::vector<std::pair <db::DPoint, db::DPoint> >::push_back, "reference-point",
tl::make_member (&std::pair <db::DPoint, db::DPoint>::first, "pcb", lay::PointConverter<db::DPoint> ()) +
tl::make_member (&std::pair <db::DPoint, db::DPoint>::second, "layout", lay::PointConverter<db::DPoint> ())
)
) +
tl::make_member (&GerberImportData::explicit_trans, "explicit-trans", lay::TransformationConverter<db::DCplxTrans> ()) +
tl::make_member (&GerberImportData::layer_properties_file, "layer-properties-file") +
tl::make_member (&GerberImportData::num_circle_points, "num-circle-points") +
tl::make_member (&GerberImportData::merge_flag, "merge-flag") +
tl::make_member (&GerberImportData::dbu, "dbu") +
tl::make_member (&GerberImportData::topcell_name, "cell-name")
);
void
GerberImportData::load (const std::string &file)
{
reset ();
current_file = file;
tl::XMLFileSource in (file);
pcb_project_structure.parse (in, *this);
}
void
GerberImportData::load (tl::InputStream &stream)
{
reset ();
current_file = std::string ();
tl::XMLStreamSource in (stream);
pcb_project_structure.parse (in, *this);
}
void
GerberImportData::save (const std::string &file)
{
tl::OutputStream os (file, tl::OutputStream::OM_Plain);
pcb_project_structure.write (os, *this);
current_file = file;
}
void
GerberImportData::from_string (const std::string &s)
{
tl::Extractor ex (s.c_str ());
while (! ex.at_end ()) {
if (ex.test ("free-layer-mapping")) {
ex.test ("=");
ex.read (free_layer_mapping);
ex.test (";");
} else if (ex.test ("invert-negative-layers")) {
ex.test ("=");
ex.read (invert_negative_layers);
ex.test (";");
} else if (ex.test ("border")) {
ex.test ("=");
ex.read (border);
ex.test (";");
} else if (ex.test ("import-mode")) {
ex.test ("=");
int m = 0;
ex.read (m);
mode = (mode_type) m;
ex.test (";");
} else if (ex.test ("base-dir")) {
ex.test ("=");
ex.read_word_or_quoted (base_dir);
ex.test (";");
} else if (ex.test ("layout-layers")) {
ex.test ("=");
layout_layers.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
layout_layers.push_back (db::LayerProperties ());
layout_layers.back ().read (ex);
ex.test (",");
}
ex.test (";");
} else if (ex.test ("mounting")) {
ex.test ("=");
std::string m;
ex.read_word (m);
mounting = (m == "top") ? MountingTop : MountingBottom;
ex.test (";");
} else if (ex.test ("num-metal-layers")) {
ex.test ("=");
ex.read (num_metal_layers);
ex.test (";");
} else if (ex.test ("num-via-types")) {
ex.test ("=");
ex.read (num_via_types);
ex.test (";");
} else if (ex.test ("artwork-files")) {
ex.test ("=");
artwork_files.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
ex.test ("(");
artwork_files.push_back (lay::GerberArtworkFileDescriptor ());
ex.read_word_or_quoted (artwork_files.back ().filename);
ex.test (")");
ex.test (",");
}
ex.test (";");
} else if (ex.test ("drill-files")) {
ex.test ("=");
drill_files.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
ex.test ("(");
drill_files.push_back (lay::GerberDrillFileDescriptor ());
ex.read (drill_files.back ().start);
ex.test (",");
ex.read (drill_files.back ().stop);
ex.test (",");
ex.read_word_or_quoted (drill_files.back ().filename);
ex.test (")");
ex.test (",");
}
ex.test (";");
} else if (ex.test ("free-files")) {
ex.test ("=");
free_files.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
ex.test ("(");
free_files.push_back (lay::GerberFreeFileDescriptor ());
ex.read_word_or_quoted (free_files.back ().filename);
ex.test (",");
while (! ex.test (")") && ! ex.at_end ()) {
int i = -1;
ex.read (i);
free_files.back ().layout_layers.push_back (i);
ex.test (",");
}
ex.test (",");
}
ex.test (";");
} else if (ex.test ("reference-points")) {
ex.test ("=");
reference_points.clear ();
while (! ex.test (";") && ! ex.at_end ()) {
double x1, y1, x2, y2;
ex.test ("(");
ex.test ("(");
ex.read (x1);
ex.test (",");
ex.read (y1);
ex.test (")");
ex.test (",");
ex.test ("(");
ex.read (x2);
ex.test (",");
ex.read (y2);
ex.test (")");
ex.test (")");
ex.test (",");
reference_points.push_back (std::make_pair (db::DPoint (x1, y1), db::DPoint (x2, y2)));
}
ex.test (";");
} else if (ex.test ("explicit-trans")) {
ex.test ("=");
ex.read (explicit_trans);
ex.test (";");
} else if (ex.test ("layer-properties-file")) {
ex.test ("=");
ex.read_word_or_quoted (layer_properties_file);
ex.test (";");
} else if (ex.test ("num-circle-points")) {
ex.test ("=");
ex.read (num_circle_points);
ex.test (";");
} else if (ex.test ("merge-flag")) {
ex.test ("=");
ex.read (merge_flag);
ex.test (";");
} else if (ex.test ("dbu")) {
ex.test ("=");
ex.read (dbu);
ex.test (";");
} else if (ex.test ("cell-name")) {
ex.test ("=");
ex.read_word_or_quoted (topcell_name);
ex.test (";");
} else {
ex.expect_end ();
}
}
}
std::string
GerberImportData::to_string () const
{
std::string s;
s += "free-layer-mapping=" + tl::to_string(free_layer_mapping) + ";";
s += "import-mode=" + tl::to_string(int (mode)) + ";";
s += "base-dir=" + tl::to_quoted_string (base_dir) + ";";
s += "invert-negative-layers=" + tl::to_string (invert_negative_layers) + ";";
s += "border=" + tl::to_string (border) + ";";
s += "layout-layers=";
for (std::vector <db::LayerProperties>::const_iterator ll = layout_layers.begin (); ll != layout_layers.end (); ++ll) {
if (ll != layout_layers.begin ()) {
s += ",";
}
s += ll->to_string ();
}
s += ";";
s += "mounting=" + std::string (mounting == MountingTop ? "top" : "bottom") + ";";
s += "num-metal-layers=" + tl::to_string (num_metal_layers) + ";";
s += "num-via-types=" + tl::to_string (num_via_types) + ";";
s += "artwork-files=";
for (std::vector <GerberArtworkFileDescriptor>::const_iterator f = artwork_files.begin (); f != artwork_files.end (); ++f) {
if (f != artwork_files.begin ()) {
s += ",";
}
s += "(" + tl::to_quoted_string (f->filename) + ")";
}
s += ";";
s += "drill-files=";
for (std::vector <GerberDrillFileDescriptor>::const_iterator f = drill_files.begin (); f != drill_files.end (); ++f) {
if (f != drill_files.begin ()) {
s += ",";
}
s += "(" + tl::to_string (f->start) + "," + tl::to_string (f->stop) + "," + tl::to_quoted_string (f->filename) + ")";
}
s += ";";
s += "free-files=";
for (std::vector <GerberFreeFileDescriptor>::const_iterator f = free_files.begin (); f != free_files.end (); ++f) {
if (f != free_files.begin ()) {
s += ",";
}
s += "(" + tl::to_quoted_string (f->filename);
for (std::vector <int>::const_iterator i = f->layout_layers.begin (); i != f->layout_layers.end (); ++i) {
s += "," + tl::to_string (*i);
}
s += ")";
}
s += ";";
s += "reference-points=";
for (std::vector <std::pair <db::DPoint, db::DPoint> >::const_iterator rp = reference_points.begin (); rp != reference_points.end (); ++rp) {
if (rp != reference_points.begin ()) {
s += ",";
}
s += "((" + tl::to_string (rp->first.x ()) + "," + tl::to_string (rp->first.y ()) + "),("
+ tl::to_string (rp->second.x ()) + "," + tl::to_string (rp->second.y ()) + "))";
}
s += ";";
s += "explicit-trans=" + explicit_trans.to_string () + ";";
s += "layer-properties-file=" + tl::to_quoted_string (layer_properties_file) + ";";
s += "num-circle-points=" + tl::to_string (num_circle_points) + ";";
s += "merge-flag=" + tl::to_string (merge_flag) + ";";
s += "dbu=" + tl::to_string (dbu) + ";";
s += "cell-name=" + tl::to_quoted_string (topcell_name) + ";";
return s;
}
// -----------------------------------------------------------------------------------------
// GerberImportDialogFileColumnEditorWidget implementation

View File

@ -32,6 +32,7 @@
#include "dbLayout.h"
#include "dbPoint.h"
#include "dbTrans.h"
#include "dbGerberImportData.h"
#include <string>
#include <vector>
@ -60,65 +61,6 @@ namespace db
namespace lay
{
struct GerberArtworkFileDescriptor
{
std::string filename;
};
struct GerberDrillFileDescriptor
{
GerberDrillFileDescriptor () : start (-1), stop (-1) { }
int start;
int stop;
std::string filename;
};
struct GerberFreeFileDescriptor
{
std::string filename;
std::vector<int> layout_layers;
};
struct GerberImportData
{
public:
GerberImportData ();
enum mode_type { ModeIntoLayout = 0, ModeSamePanel, ModeNewPanel };
enum mounting_type { MountingTop = 0, MountingBottom };
bool invert_negative_layers;
double border;
bool free_layer_mapping;
mode_type mode;
std::string base_dir;
std::string current_file;
std::vector <db::LayerProperties> layout_layers;
mounting_type mounting;
int num_metal_layers;
int num_via_types;
std::vector <GerberArtworkFileDescriptor> artwork_files;
std::vector <GerberDrillFileDescriptor> drill_files;
std::vector <GerberFreeFileDescriptor> free_files;
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
db::DCplxTrans explicit_trans;
std::string layer_properties_file;
int num_circle_points;
bool merge_flag;
double dbu;
std::string topcell_name;
std::string get_layer_properties_file () const;
void setup_importer (db::GerberImporter *importer);
void reset ();
void load (tl::InputStream &stream);
void load (const std::string &file);
void save (const std::string &file);
void from_string (const std::string &s);
std::string to_string () const;
};
// The item editor for the file column
class GerberImportDialogFileColumnEditorWidget
: public QFrame

203
src/tl/tl/atomic/atomic.h Normal file
View File

@ -0,0 +1,203 @@
//----------------------------------------------------------------------------
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
// this software, either in source code form or as a compiled binary, for any
// purpose, commercial or non-commercial, and by any means.
//
// In jurisdictions that recognize copyright laws, the author or authors of
// this software dedicate any and all copyright interest in the software to the
// public domain. We make this dedication for the benefit of the public at
// large and to the detriment of our heirs and successors. We intend this
// dedication to be an overt act of relinquishment in perpetuity of all present
// and future rights to this software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org/>
//-----------------------------------------------------------------------------
#ifndef ATOMIC_ATOMIC_H_
#define ATOMIC_ATOMIC_H_
// Macro for disallowing copying of an object.
#if __cplusplus >= 201103L
#define ATOMIC_DISALLOW_COPY(T) \
T(const T&) = delete; \
T& operator=(const T&) = delete;
#else
#define ATOMIC_DISALLOW_COPY(T) \
T(const T&); \
T& operator=(const T&);
#endif
// A portable static assert.
#if __cplusplus >= 201103L
#define ATOMIC_STATIC_ASSERT(condition, message) \
static_assert((condition), message)
#else
// Based on: http://stackoverflow.com/a/809465/5778708
#define ATOMIC_STATIC_ASSERT(condition, message) \
_impl_STATIC_ASSERT_LINE(condition, __LINE__)
#define _impl_PASTE(a, b) a##b
#ifdef __GNUC__
#define _impl_UNUSED __attribute__((__unused__))
#else
#define _impl_UNUSED
#endif
#define _impl_STATIC_ASSERT_LINE(condition, line) \
typedef char _impl_PASTE( \
STATIC_ASSERT_failed_, \
line)[(2 * static_cast<int>(!!(condition))) - 1] _impl_UNUSED
#endif
#if defined(__GNUC__) || defined(__clang__) || defined(__xlc__)
#define ATOMIC_USE_GCC_INTRINSICS
#elif defined(_MSC_VER)
#define ATOMIC_USE_MSVC_INTRINSICS
#include "atomic_msvc.h"
#elif __cplusplus >= 201103L
#define ATOMIC_USE_CPP11_ATOMIC
#include <atomic>
#else
#error Unsupported compiler / system.
#endif
namespace atomic {
template <typename T>
class atomic {
public:
ATOMIC_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 ||
sizeof(T) == 8,
"Only types of size 1, 2, 4 or 8 are supported");
atomic() : value_(static_cast<T>(0)) {}
explicit atomic(const T value) : value_(value) {}
/// @brief Performs an atomic increment operation (value + 1).
/// @returns The new value of the atomic object.
T operator++() {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_add_fetch(&value_, 1, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
return msvc::interlocked<T>::increment(&value_);
#else
return ++value_;
#endif
}
/// @brief Performs an atomic decrement operation (value - 1).
/// @returns The new value of the atomic object.
T operator--() {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_sub_fetch(&value_, 1, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
return msvc::interlocked<T>::decrement(&value_);
#else
return --value_;
#endif
}
/// @brief Performs an atomic compare-and-swap (CAS) operation.
///
/// The value of the atomic object is only updated to the new value if the
/// old value of the atomic object matches @c expected_val.
///
/// @param expected_val The expected value of the atomic object.
/// @param new_val The new value to write to the atomic object.
/// @returns True if new_value was written to the atomic object.
bool compare_exchange(const T expected_val, const T new_val) {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
T e = expected_val;
return __atomic_compare_exchange_n(
&value_, &e, new_val, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
const T old_val =
msvc::interlocked<T>::compare_exchange(&value_, new_val, expected_val);
return (old_val == expected_val);
#else
T e = expected_val;
return value_.compare_exchange_weak(e, new_val);
#endif
}
/// @brief Performs an atomic set operation.
///
/// The value of the atomic object is unconditionally updated to the new
/// value.
///
/// @param new_val The new value to write to the atomic object.
void store(const T new_val) {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
__atomic_store_n(&value_, new_val, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
(void)msvc::interlocked<T>::exchange(&value_, new_val);
#else
value_.store(new_val);
#endif
}
/// @returns the current value of the atomic object.
/// @note Be careful about how this is used, since any operations on the
/// returned value are inherently non-atomic.
T load() const {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_load_n(&value_, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
// TODO(m): Is there a better solution for MSVC?
return value_;
#else
return value_;
#endif
}
/// @brief Performs an atomic exchange operation.
///
/// The value of the atomic object is unconditionally updated to the new
/// value, and the old value is returned.
///
/// @param new_val The new value to write to the atomic object.
/// @returns the old value.
T exchange(const T new_val) {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_exchange_n(&value_, new_val, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
return msvc::interlocked<T>::exchange(&value_, new_val);
#else
return value_.exchange(new_val);
#endif
}
T operator=(const T new_value) {
store(new_value);
return new_value;
}
operator T() const {
return load();
}
private:
#if defined(ATOMIC_USE_GCC_INTRINSICS) || defined(ATOMIC_USE_MSVC_INTRINSICS)
volatile T value_;
#else
std::atomic<T> value_;
#endif
ATOMIC_DISALLOW_COPY(atomic)
};
} // namespace atomic
// Undef temporary defines.
#undef ATOMIC_USE_GCC_INTRINSICS
#undef ATOMIC_USE_MSVC_INTRINSICS
#undef ATOMIC_USE_CPP11_ATOMIC
#endif // ATOMIC_ATOMIC_H_

View File

@ -0,0 +1,238 @@
//-----------------------------------------------------------------------------
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
// this software, either in source code form or as a compiled binary, for any
// purpose, commercial or non-commercial, and by any means.
//
// In jurisdictions that recognize copyright laws, the author or authors of
// this software dedicate any and all copyright interest in the software to the
// public domain. We make this dedication for the benefit of the public at
// large and to the detriment of our heirs and successors. We intend this
// dedication to be an overt act of relinquishment in perpetuity of all present
// and future rights to this software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org/>
//-----------------------------------------------------------------------------
#ifndef ATOMIC_ATOMIC_MSVC_H_
#define ATOMIC_ATOMIC_MSVC_H_
// Define which functions we need (don't include <intrin.h>).
extern "C" {
short _InterlockedIncrement16(short volatile*);
long _InterlockedIncrement(long volatile*);
__int64 _InterlockedIncrement64(__int64 volatile*);
short _InterlockedDecrement16(short volatile*);
long _InterlockedDecrement(long volatile*);
__int64 _InterlockedDecrement64(__int64 volatile*);
char _InterlockedExchange8(char volatile*, char);
short _InterlockedExchange16(short volatile*, short);
long __cdecl _InterlockedExchange(long volatile*, long);
__int64 _InterlockedExchange64(__int64 volatile*, __int64);
char _InterlockedCompareExchange8(char volatile*, char, char);
short _InterlockedCompareExchange16(short volatile*, short, short);
long __cdecl _InterlockedCompareExchange(long volatile*, long, long);
__int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64);
};
// Define which functions we want to use as inline intriniscs.
#pragma intrinsic(_InterlockedIncrement)
#pragma intrinsic(_InterlockedIncrement16)
#pragma intrinsic(_InterlockedDecrement)
#pragma intrinsic(_InterlockedDecrement16)
#pragma intrinsic(_InterlockedCompareExchange)
#pragma intrinsic(_InterlockedCompareExchange8)
#pragma intrinsic(_InterlockedCompareExchange16)
#pragma intrinsic(_InterlockedExchange)
#pragma intrinsic(_InterlockedExchange8)
#pragma intrinsic(_InterlockedExchange16)
#if defined(_M_X64)
#pragma intrinsic(_InterlockedIncrement64)
#pragma intrinsic(_InterlockedDecrement64)
#pragma intrinsic(_InterlockedCompareExchange64)
#pragma intrinsic(_InterlockedExchange64)
#endif // _M_X64
namespace atomic {
namespace msvc {
template <typename T, size_t N = sizeof(T)>
struct interlocked {
};
template <typename T>
struct interlocked<T, 1> {
static inline T increment(T volatile* x) {
// There's no _InterlockedIncrement8().
char old_val, new_val;
do {
old_val = static_cast<char>(*x);
new_val = old_val + static_cast<char>(1);
} while (_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
new_val,
old_val) != old_val);
return static_cast<T>(new_val);
}
static inline T decrement(T volatile* x) {
// There's no _InterlockedDecrement8().
char old_val, new_val;
do {
old_val = static_cast<char>(*x);
new_val = old_val - static_cast<char>(1);
} while (_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
new_val,
old_val) != old_val);
return static_cast<T>(new_val);
}
static inline T compare_exchange(T volatile* x,
const T new_val,
const T expected_val) {
return static_cast<T>(
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(x),
static_cast<const char>(new_val),
static_cast<const char>(expected_val)));
}
static inline T exchange(T volatile* x, const T new_val) {
return static_cast<T>(_InterlockedExchange8(
reinterpret_cast<volatile char*>(x), static_cast<const char>(new_val)));
}
};
template <typename T>
struct interlocked<T, 2> {
static inline T increment(T volatile* x) {
return static_cast<T>(
_InterlockedIncrement16(reinterpret_cast<volatile short*>(x)));
}
static inline T decrement(T volatile* x) {
return static_cast<T>(
_InterlockedDecrement16(reinterpret_cast<volatile short*>(x)));
}
static inline T compare_exchange(T volatile* x,
const T new_val,
const T expected_val) {
return static_cast<T>(
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(x),
static_cast<const short>(new_val),
static_cast<const short>(expected_val)));
}
static inline T exchange(T volatile* x, const T new_val) {
return static_cast<T>(
_InterlockedExchange16(reinterpret_cast<volatile short*>(x),
static_cast<const short>(new_val)));
}
};
template <typename T>
struct interlocked<T, 4> {
static inline T increment(T volatile* x) {
return static_cast<T>(
_InterlockedIncrement(reinterpret_cast<volatile long*>(x)));
}
static inline T decrement(T volatile* x) {
return static_cast<T>(
_InterlockedDecrement(reinterpret_cast<volatile long*>(x)));
}
static inline T compare_exchange(T volatile* x,
const T new_val,
const T expected_val) {
return static_cast<T>(
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(x),
static_cast<const long>(new_val),
static_cast<const long>(expected_val)));
}
static inline T exchange(T volatile* x, const T new_val) {
return static_cast<T>(_InterlockedExchange(
reinterpret_cast<volatile long*>(x), static_cast<const long>(new_val)));
}
};
template <typename T>
struct interlocked<T, 8> {
static inline T increment(T volatile* x) {
#if defined(_M_X64)
return static_cast<T>(
_InterlockedIncrement64(reinterpret_cast<volatile __int64*>(x)));
#else
// There's no _InterlockedIncrement64() for 32-bit x86.
__int64 old_val, new_val;
do {
old_val = static_cast<__int64>(*x);
new_val = old_val + static_cast<__int64>(1);
} while (_InterlockedCompareExchange64(
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
old_val);
return static_cast<T>(new_val);
#endif // _M_X64
}
static inline T decrement(T volatile* x) {
#if defined(_M_X64)
return static_cast<T>(
_InterlockedDecrement64(reinterpret_cast<volatile __int64*>(x)));
#else
// There's no _InterlockedDecrement64() for 32-bit x86.
__int64 old_val, new_val;
do {
old_val = static_cast<__int64>(*x);
new_val = old_val - static_cast<__int64>(1);
} while (_InterlockedCompareExchange64(
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
old_val);
return static_cast<T>(new_val);
#endif // _M_X64
}
static inline T compare_exchange(T volatile* x,
const T new_val,
const T expected_val) {
return static_cast<T>(_InterlockedCompareExchange64(
reinterpret_cast<volatile __int64*>(x),
static_cast<const __int64>(new_val),
static_cast<const __int64>(expected_val)));
}
static inline T exchange(T volatile* x, const T new_val) {
#if defined(_M_X64)
return static_cast<T>(
_InterlockedExchange64(reinterpret_cast<volatile __int64*>(x),
static_cast<const __int64>(new_val)));
#else
// There's no _InterlockedExchange64 for 32-bit x86.
__int64 old_val;
do {
old_val = static_cast<__int64>(*x);
} while (_InterlockedCompareExchange64(
reinterpret_cast<volatile __int64*>(x), new_val, old_val) !=
old_val);
return static_cast<T>(old_val);
#endif // _M_X64
}
};
} // namespace msvc
} // namespace atomic
#endif // ATOMIC_ATOMIC_MSVC_H_

View File

@ -0,0 +1,78 @@
//-----------------------------------------------------------------------------
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
// this software, either in source code form or as a compiled binary, for any
// purpose, commercial or non-commercial, and by any means.
//
// In jurisdictions that recognize copyright laws, the author or authors of
// this software dedicate any and all copyright interest in the software to the
// public domain. We make this dedication for the benefit of the public at
// large and to the detriment of our heirs and successors. We intend this
// dedication to be an overt act of relinquishment in perpetuity of all present
// and future rights to this software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org/>
//-----------------------------------------------------------------------------
#ifndef ATOMIC_SPINLOCK_H_
#define ATOMIC_SPINLOCK_H_
#include "atomic/atomic.h"
namespace atomic {
class spinlock {
public:
spinlock() : value_(0) {}
/// @brief Acquire the lock (blocking).
/// @note Trying to acquire a lock that is already held by the calling thread
/// will dead-lock (block indefinitely).
void lock() {
while (!value_.compare_exchange(UNLOCKED, LOCKED))
;
}
/// @brief Release the lock.
/// @note It is an error to release a lock that has not been previously
/// acquired.
void unlock() { value_.store(UNLOCKED); }
private:
static const int UNLOCKED = 0;
static const int LOCKED = 1;
atomic<int> value_;
ATOMIC_DISALLOW_COPY(spinlock)
};
class lock_guard {
public:
/// @brief The constructor acquires the lock.
/// @param lock The spinlock that will be locked.
explicit lock_guard(spinlock& lock) : lock_(lock) {
lock_.lock();
}
/// @brief The destructor releases the lock.
~lock_guard() {
lock_.unlock();
}
private:
spinlock& lock_;
ATOMIC_DISALLOW_COPY(lock_guard)
};
} // namespace atomic
#endif // ATOMIC_SPINLOCK_H_