Fast computation of logic gates - c++

I created the following code to compute the result of a logic gate (AND, OR, NOT). The function will be used in a circuit simulation where the circuits are read from a netlist file. A circuit could consist of up to 50000 logic gates.
Based on the fact that this function is often called during the simulation I would like to know if it could be implemented in another way so the generated machine code would be more efficient?
A logic gate could have more than two inputs (except NOT with only one input) but most logic gates have only two. So I thought about testing for two inputs and then write something like this: return input->predecessors[0]->result && return input->predecessors[1]->result; and return input->predecessors[0]->result || return input->predecessors[1]->result; But this would probably introduce new branches. The number of the inputs could be stored in the Node directly to prevent the call of the size() method.
#include <vector>
enum class NodeType { NOT, AND, OR };
struct Node {
NodeType type;
bool result;
std::vector<Node *> predecessors;
};
bool evaluate(Node *input) {
switch (input->type) {
case NodeType::NOT: {
return !input->predecessors[0]->result;
}
case NodeType::AND: {
bool result = true;
for (const auto &node : input->predecessors) {
result = result && node->result;
}
return result;
}
case NodeType::OR: {
bool result = false;
for (const auto &node : input->predecessors) {
result = result || node->result;
}
return result;
}
};
};

I'd be tempted to get the first input and merge its state into the switch(); like:
bool result = input->predecessors[0];
switch((input->type << 1) | result) {
case (NodeType::NOT << 1) | false:
return true;
case (NodeType::NOT << 1) | true:
return false;
case (NodeType::AND << 1) | false:
return false;
case (NodeType::OR << 1) | true:
return true;
case (NodeType::AND << 1) | true: {
for (const auto &node : input->predecessors) { // Note: Can skip 1st iteration
result = result && node->result;
if(result == false) {
return false;
}
}
return true;
}
case (NodeType::OR << 1) | false:
for (const auto &node : input->predecessors) { // Note: Can skip 1st iteration
result = result || node->result;
if(result == true) {
return true;
}
}
return false;
}
The hope being that the compiler will be able to convert this into a jump table (e.g. a single "jmp [table+rax*8]" instruction replacing all the switch() and half the rest of the code).
WARNING: For this to work you have to make sure that input->predecessors[0] uses 1 for "true" (and that no other value is used for true). If that is a potential concern; you can use bool result = !!input->predecessors[0];

It really looks like what you are doing is an interface.
struct Node {
std::vector<Node *> predecessors;
virtual bool evaluate() const;
};
struct NodeNot : Node {
bool evaluate() const {
return !input->predecessors[0]->result;
}
};
struct NodeAnd : Node {
bool evaluate() const {
for (const auto &node : input->predecessors) {
if(!node->result) {
// there is no need to accumulate the result
// fail fast
return false;
}
}
return true;
}
};
struct NodeOr : Node {
bool evaluate() const {
for (const auto &node : input->predecessors) {
if (node->result) {
return true;
}
}
return false;
}
};
That way you eliminate the need for the switch completely and achieve same result with just a single virtual call. It may be faster or slower method then the switch, it really depends on many factors and how good you are caching the result in Node::result member. Profile your code to be sure what works best.

I was looking at using std::variant. Still a bit hacky, because I'm using void pointers... any help on cleaning this up would be nice
#include <tuple>
#include <variant>
#include <stdexcept>
#include <assert.h>
using vcpc = void const* const;
struct NOT { vcpc ptr; };
struct OR { vcpc ptr1; vcpc ptr2; };
struct AND { vcpc ptr1; vcpc ptr2; };
using Node = std::variant<NOT, OR, AND, bool>;
// from https://en.cppreference.com/w/cpp/utility/variant/visit
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
using Ncpc = Node const* const;
constexpr bool evaluate(Ncpc input) {
return std::visit(overloaded{
[](NOT const& arg) { return !evaluate((Ncpc)arg.ptr); },
[](OR const& arg) { return evaluate((Ncpc)arg.ptr1) || evaluate((Ncpc)arg.ptr2); },
[](AND const& arg) { return evaluate((Ncpc)arg.ptr1) && evaluate((Ncpc)arg.ptr2); },
[](bool arg) { return arg; },
}, *input);
}
int main() {
Node const isTrue{ true };
Node const invTrue{ NOT{&isTrue} };
assert(evaluate(&invTrue) == false);
Node const andTrueFalse{ AND{&isTrue, &invTrue} };
assert(evaluate(&andTrueFalse) == false);
Node const orTrueFalse{ OR{&isTrue, &andTrueFalse} };
assert(evaluate(&orTrueFalse) == true);
}

Related

function-style-cast in Template Meta programming

Code taken from the book Template Metaprogramming with C++, it doesn't compile i tried visual studio 22 i get the error:
Error C2440
\<function-style-cast\>'
: cannot convert from 'initializer list' to 'n713::async_bool'chapter_07
see code:
class async_bool{
std::function<bool()> check;
public:explicit async_bool() = delete;
async_bool(std::function<bool()> checkIt): check(checkIt){ }
async_bool(bool val)
: check([val]() {return val; })
{ }
static async_bool yes() {
return async_bool(
[]() { return true; } );
}
static async_bool no() {
return async_bool(
[]() { return false; } );
}
bool operator&&(bool fore) const { return fore && check(); }
bool operator!() const { return !check(); }
operator bool() const { return check(); }
};
int main(){
async_bool b1 = async_bool(false); //async_bool b1{ false };
async_bool b2 = async_bool(true);// async_bool b2{ true };
async_bool b3{ {std::cout << "Y/N? "; char c; std::cin >> c; return c == 'Y' || c == 'y'; }
if (b1) { std::cout << "b1 is true\n"; }
if (b2) { std::cout << "b2 is true\n"; }
if (b3) { std::cout << "b3 is true\n"; }
return 0;
};
tried c++20 with visual studio
tried g++ in ubuntu-> gave different errors but still didnt compile, managed to fix it i think by changing the code to the following:
class async_bool
{
using check = std::function<bool()>;
check dec_;
public:
async_bool() = delete;
async_bool(check dec) : dec_{ std::move(dec) } {}
async_bool(bool val) :dec_([val]() {return val; }) {}
static async_bool yes() {
const auto lam = []() { return true; };
async_bool async_bool_yes(lam());
return async_bool_yes;
}
static async_bool no() {
const auto lam = []() { return false; };
async_bool async_bool_no(lam());
return async_bool_no;
}
bool operator&&(bool fore) const { return fore && dec_(); }
bool operator!() const { return !dec_(); }
operator bool() const { return dec_(); }
};
and in main:
int main()
{
async_bool b1( false );
async_bool b2{ true };
const auto lam = []() { []() {std::cout << "Y/N? "; char c; std::cin >> c; return c == 'Y' || c == 'y'; }; };
async_bool b3{lam};
return 0;
}
Lambdas that don't capture anything are convertible both to std::function and to bool (via conversion to function pointer). You can add an additional templated constructor to make compiler prefer conversion to std::function:
template <typename F,
typename = std::enable_if_t<std::is_convertible_v<F,std::function<bool()>>>>
async_bool(F checkIt): check(checkIt) { }
Alternatively, instead of SFINAE you can use concepts.
(Edit: it's interesting that removing the constructor from std::function removes the ambiguity, but every construction with a { <captureless-lambda> } still fails because conversion from a function pointer to a bool is forbidden using braces, but the corresponding candidate it is not removed from overload-set. Maybe language lawyers can explain this bit if you're interested.

TransformerClangTidyCheck drops required parentheses around bound `expr()`

I'd like to rename a function on one of the classes:
class Container {
public:
int count() const; // old
int size() const; // new
};
So I've written a TransformerClangTidyCheck along the lines of the tutorial (https://clang.llvm.org/docs/ClangTransformerTutorial.html#example-rewriting-method-calls):
ReproParenIssueCheck::ReproParenIssueCheck(llvm::StringRef Name, ClangTidyContext *Context)
: utils::TransformerClangTidyCheck(Name, Context)
{
const std::string o = "object";
auto hasTypeIgnoringPointer = [](auto type) { return anyOf(hasType(type), hasType(pointsTo(type))); };
auto derivedFromClass = [&](StringRef Class) {
auto exprOfDeclaredType = [&](auto decl) {
return hasTypeIgnoringPointer(hasUnqualifiedDesugaredType(recordType(hasDeclaration(decl))));
};
return exprOfDeclaredType(cxxRecordDecl(isSameOrDerivedFrom(hasName(Class))));
};
auto renameMethod = [&] (StringRef Class, StringRef from, StringRef to) {
return makeRule(cxxMemberCallExpr(on(expr(derivedFromClass(Class)).bind(o)),
callee(cxxMethodDecl(hasName(from), parameterCountIs(0)))),
changeTo(cat(access(o, cat(to)), "()")),
cat("use '", to, "' instead of '", from, "'"));
};
setRule(renameMethod("Container", "count", "size"));
}
This works:
int test_ok(const Container *p) {
- return p->count();
+ return p->size();
}
except that changeTo() is losing the required ParenExpr in the expr() bound to o:
int test_fail(const void *p) {
- return ((const Container*)p)->count();
+ return ((const Container*)p)->size(); // expected
+ return (const Container*)p->size(); // actual
}
Bug in changeTo() or am I missing something? It looks like any ParenExpr is dropped:
int test_fail2(const Container &c) {
- return (c).count();
+ return (c).size(); // expected
+ return c.size(); // actual
}
It turns out that the on() matcher drops the parentheses:
AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
InnerMatcher) {
const Expr *ExprNode = Node.getImplicitObjectArgument()
->IgnoreParenImpCasts(); // <-- HERE
return (ExprNode != nullptr &&
InnerMatcher.matches(*ExprNode, Finder, Builder));
}
If I create a new matcher that only ignores implicit casts:
AST_MATCHER_P(CXXMemberCallExpr, onIgnoringImpCasts, Matcher<Expr>,
InnerMatcher) {
const Expr *ExprNode = Node.getImplicitObjectArgument()
->IgnoreImpCasts();
return (ExprNode != nullptr &&
InnerMatcher.matches(*ExprNode, Finder, Builder));
and use that instead of on(), both test cases pass.

setting return of coroutine into a variable inside another coroutine makes compiler try to convert promise types

I am currently on an issue where I simply try to co_await coroutine B to save the return of it into a variable inside coroutine A but it tries to convert the promise type of A to the promise type of B.
forStackoverflow.cpp: In function ‘myTask<std::optional<int> > getValue(std::vector<int>&, int, bool)’:
forStackoverflow.cpp:68:60: error: cannot convert ‘coroutine_handle<promise_type<std::optional<int>>>’ to ‘coroutine_handle<promise_type<int>>’
68 | leaf = co_await suspendableLocateValue(key, array, true);
| ^
forStackoverflow.cpp:42:58: note: initializing argument 1 of ‘void myTask<T>::await_suspend(std::__n4861::coroutine_handle<myTask<T>::promise_type>) const [with T = int]’
42 | void await_suspend(std::coroutine_handle<promise_type> coro) const noexcept { coro.promise().boolIsDone = true; }
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
#include <iostream>
#include <optional>
#include <utility>
#include <vector>
#include <concepts>
#include <coroutine>
#include <exception>
#include <iostream>
#include <vector>
template <typename T>
struct myTask {
struct promise_type {
T value_;
~promise_type() {}
myTask<T> get_return_object() {
return myTask<T> {
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend()
{
boolIsDone = true;
return {};
}
void unhandled_exception() { std::terminate(); }
std::suspend_always return_value(auto value) {
value_ = value;
return {};
}
bool boolIsDone = false;
auto isDone() { return boolIsDone; }
};
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<promise_type> coro) const noexcept { coro.promise().boolIsDone = true; }
void await_resume() const noexcept {}
std::coroutine_handle<promise_type> h_;
operator std::coroutine_handle<promise_type>() const { return h_; }
};
myTask<int> suspendableLocateValue(int key, std::vector<int>& array, bool interleave)
{
int currentInt = 0;
if (interleave = true)
{
//do something here
co_await std::suspend_always{};
}
currentInt = array.at(key);
co_return currentInt;
}
myTask<std::optional<int>> getValue(std::vector<int>& array, int key, bool interleave)
{
//int result = array.at(key);
int leaf;
if (interleave = true)
{
leaf = co_await suspendableLocateValue(key, array, true);
}
co_return std::make_optional(leaf);
}
void minimalInterleavedExecution(std::vector<int>& lookup,
std::vector<int>& keys,
std::vector<std::optional<int>>& results,
int groupsize)
{
std::vector<std::coroutine_handle<myTask<std::optional<int>>::promise_type>> handles;
for (int i = 0; i < groupsize; ++i)
{
handles.push_back(getValue(lookup, keys.at(i), true));
}
int notDone = groupsize;
int i = groupsize;
while (notDone > 0)
{
for (int handleIndex = 0; handleIndex < handles.size(); ++handleIndex)
{
if (!handles.at(handleIndex).promise().isDone())
{
handles.at(handleIndex).resume();
}
else
{
results.push_back(handles.at(handleIndex).promise().value_);
if (i < keys.size())
{
handles.at(handleIndex) = getValue(lookup, keys.at(i), true);
++i;
}
else
{
--notDone;
handles.erase(handles.begin() + handleIndex);
--handleIndex;
}
}
}
}
}
int main()
{
std::vector<int> lookup = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
std::vector<int> keys = {4, 2, 0, 6, 9, 0};
std::vector<std::optional<int>> results;
minimalInterleavedExecution(lookup, keys, results, 4);
}
My original code actually involves a B+Tree and suspendableLocateValue is supposed to be a function that finds and returns a leaf of type myTask<Node> with a given key and getValue is supposed to set the return value of the Node-returning function to a new Node and gets the specific value from the node to return it as an optional.
In function with return value of myTask<std::optional<int>> there is a call
leaf = co_await suspendableLocateValue(key, array, true);
and suspendableLocateValue returns myTask<int>. But await_suspend is not templated and therefore could not be used:
void await_suspend(std::coroutine_handle<promise_type> coro) const noexcept
So myTask<U> could be awaited only in myTask<U> coroutines.
When co_await something is encountered in the coroutine there are several steps that compiler do to determine what is the meaning of that expression:
Is there await_transform in enclosing coroutine?
Is there operator co_await?
Otherwise (your case) it generates code that has something.await_suspend(h), where h is a std::coroutine_handle<P> and P is a type of an enclosing coroutine's promise.
In your example:
something is myTask<int>
h is std::coroutine_handle<myTask<std::optional<int>>::promise_type>
so there is a call to myTask<int>::await_suspend(std::coroutine_handle<myTask<std::optional<int>>::promise_type>) but there is no such function. Compiler tries to convert std::coroutine_handle<myTask<std::optional<int>>::promise_type> to actual argument type of await_suspend (std::coroutine_handle<myTask<int>::promise_type>) and writes an error about it.

Auto generating conditional expression from list/map

I am working on a program, that has to initialize many different objects according to a list that defines which type each object is.
The code that does this task looks like this:
// name is one entry of the type list
// itemList is a std::vector where the new items are appended
if(name == "foo")
{
initItem<FooObject>(itemList);
}
else if(name == "bar")
{
initItem<BarObject>(itemList);
}
else if(name == "baz")
{
initItem<Object3>(itemList);
}
....
initItem(ItemList) allocates an object of type T and appends it to itemList.
At other place in the code there are similar conditional statements for the different object types.
At the moment for each new object type added I have to add a new else if to all the conditional statements which is kind of annoying.
Is there a way to just define some kind of map somewhere that holds the assignment like
"foo", FooObject,
"bar", BarObject,
"baz", Object3,
and then template/auto-generate (maybe by preprocessor) the if-else statements so i don't have to setup them by hand every time?
Edit: Here is the whole method that contains the code snipset (there are many more else if() statements that all work according to the same principal.
bool Model::xml2Tree(const pugi::xml_node &xml_node, std::vector<TreeItem*> &parents)
{
bool all_ok = true;
bool sucess;
pugi::xml_node child_node = xml_node.first_child();
for (; child_node; child_node = child_node.next_sibling())
{
sucess = true;
bool ok = false;
std::string name = child_node.name();
if(name == "foo")
{
ok = initTreeItem<FooObject>(child_node, parents);
}
else if(name == "bar")
{
ok = initTreeItem<BarObject>(child_node, parents);
}
...
...
...
else
{
ok = false;
std::cout << "Unknown Element" << std::endl;
continue;
}
if(!sucess)
{
continue;
}
all_ok = all_ok && ok;
// recursiv
ok = xml2Tree(child_node, parents);
all_ok = all_ok && ok;
}
parents.pop_back();
return all_ok;
}
template<class T>
bool Model::initTreeItem(const pugi::xml_node &xml_node,
std::vector<TreeItem *> &parents)
{
bool ok = false;
T *pos = new T(parents.back());
parents.back()->appendChild(pos);
ok = pos->initFromXml(xml_node);
parents.push_back(pos);
return ok;
}
Firstly, you can encode your mapping in the type system as follows:
template <typename T>
struct type_wrapper { using type = T; };
template <typename T>
inline constexpr type_wrapper<T> t{};
template <typename K, typename V>
struct pair
{
K _k;
V _v;
constexpr pair(K k, V v) : _k{k}, _v{v} { }
};
template <typename... Ts>
struct map : Ts...
{
constexpr map(Ts... xs) : Ts{xs}... { }
};
constexpr auto my_map = map{
pair{[]{ return "foo"; }, t<FooObject>},
pair{[]{ return "bar"; }, t<BarObject>},
pair{[]{ return "baz"; }, t<Object3>}
};
We're using lambdas as they're implicitly constexpr in C++17, in order to simulate "constexpr arguments". If you do not require this, you can create a constexpr wrapper over a string literal and use that instead.
You can then go through the mapping with something like this:
template <typename... Pairs>
void for_kv_pairs(const std::string& name, map<Pairs...> m)
{
([&]<typename K, typename V>(const pair<K, V>& p)
{
if(name == p._k())
{
initItem<typename V::type>();
}
}(static_cast<const Pairs&>(m)), ...);
}
This is using a fold expression over the comma operator plus C++20 template syntax in lambdas. The latter can be replaced by providing an extra implementation function to retrieve K and V from pair pre-C++20.
Usage:
template <typename X>
void initItem()
{
std::cout << typeid(X).name() << '\n';
}
struct FooObject { };
struct BarObject { };
struct Object3 { };
constexpr auto my_map = map{
pair{[]{ return "foo"; }, t<FooObject>},
pair{[]{ return "bar"; }, t<BarObject>},
pair{[]{ return "baz"; }, t<Object3>}
};
int main()
{
for_kv_pairs("bar", my_map);
}
Output:
9BarObject
live example on wandbox.org
You can use higher-order macros (or x-macros) to generate code like that, for example:
#define each_item(item, sep) \
item("foo", FooObject) sep \
item("bar", BarObject) sep \
item("baz", Object3)
#define item_init(item_name, item_type) \
if (name == item_name) { \
initItem<item_type>(itemList); \
}
each_item(item_init, else)

Is it possible to define a variable that can be set only once?

I know of const, that can't be changed after creation. But I was wondering if there is a way to declare a variable that you set only once and after that, can't overwrite.
In my code, I would like to avoid the bool variable by having an nFirst that, once set to nIdx, can't be set to the new value of nIdx.
My code:
int nFirst = 0;
int nIdx = 0;
bool bFound = false;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo!= NULL)
{
pFoo->DoSmth();
if (!bFound)
{
nFirst= nIdx;
bFound = true;
}
}
nIdx++;
}
Pretty easy to roll your own.
template<typename T>
class SetOnce
{
public:
SetOnce(T init) : m_Val(init)
{}
SetOnce<T>& operator=(const T& other)
{
std::call_once(m_OnceFlag, [&]()
{
m_Val = other;
});
return *this;
}
const T& get() { return m_Val; }
private:
T m_Val;
std::once_flag m_OnceFlag;
};
Then just use the wrapper class for your variable.
SetOnce<int> nFirst(0);
nFirst= 1;
nFirst= 2;
nFirst= 3;
std::cout << nFirst.get() << std::endl;
Outputs:
1
I would like to avoid the bool variable
You can check nFirst itself, based on the fact that it won't be set a negative number. Such as:
int nFirst = -1;
int nIdx = 0;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo != NULL)
{
pFoo->DoSmth();
if (nFirst == -1)
{
nFirst = nIdx;
}
}
nIdx++;
}
Similar to cocarin's, but throws exception instead of silently ignoring assignment:
template <typename T, typename Counter = unsigned char>
class SetOnce {
public:
SetOnce(const T& initval = T(), const Counter& initcount = 1):
val(initval), counter(initcount) {}
SetOnce(const SetOnce&) = default;
SetOnce<T, Counter>& operator=(const T& newval) {
if (counter) {
--counter;
val = newval;
return *this;
}
else throw "Some error";
}
operator const T&() const { return val; } // "getter"
protected:
T val;
Counter counter;
};
Usage:
SetOnce<int> x = 42;
std::cout << x << '\n'; // => 42
x = 4;
// x = 5; // fails
std::cout << x << '\n'; // => 4
Online demo
Your question is about avoiding the bool but also implies the need for const-ness.
To avoid the bool, I'd use a boost::optional like this:
boost::optional<int> nFirst;
// ..
if (!nFirst) nFirst = nIdx;
// and now you can use *nFirst to get its value
Then, you can enforce logical (rather than literal) const-ness like this:
const boost::optional<int> nFirst;
// ..
if (!nFirst) const_cast<boost::optional<int>&>(nFirst) = nIdx;
// you can use *nFirst to get the value, any attempt to change it would cause a compile-time error
Using const_cast is not the safest practice, but in your particular case and as long as you only do it once it'd be OK. It simplifies both your code and your intentions: you do want a const, it's just that you want to defer it's initialisation for a bit.
Now, as songyuanyao suggested, you could directly use an int instead of a boost::optional, but the latter makes your intention explicit so I think it's better this way. In the end of day this is C++ while songyuanyao's solution is really a C-style one.
This is set once template. You can use this class as assurance that the value will be set and saved only once. Every next try will be canceled.
#include <iostream>
using namespace std;
template <class T>
class SetOnce;
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj );
template <class T>
class SetOnce
{
public:
SetOnce() {set = false; }
~SetOnce() {}
void SetValue(T newValue) { value = !set ? newValue : value; set = true; }
private:
T value;
bool set;
friend std::ostream& operator<< <>( ostream& os, const SetOnce& Obj );
public:
SetOnce<T>& operator=( const T& newValue )
{
this->SetValue(newValue);
return *this;
}
};
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj )
{
os << Obj.value;
return os;
}
Use case:
int main()
{
SetOnce<bool> bvar;
SetOnce<int> ivar;
SetOnce<std::string> strvar;
std::cout<<"initial values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = false; //bvar.SetValue(false);
ivar = 45; //ivar.SetValue(45);
strvar = "Darth Vader"; //strvar.SetValue("Darth Vader");
std::cout<<"set values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = true; //bvar.SetValue(true);
ivar = 0; //ivar.SetValue(0);
strvar = "Anakin"; //strvar.SetValue("Anakin");
std::cout<<"set again values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
return 0;
}