Mayank Jain Production Engineer at Facebook Inc.

Check CPU Support for a feature

At times we need to check cpu support for a particular feature, for example: We may need to check in our code if the CPU my code is running on supports AVX or not. To check this we can use compiler Intrinstics. One such intrinsic for gcc/clang (I am not sure if other compilers support this) is __builtin_cpu_supports. This instrinsic returns true if the hardware supports the feature given as input the the function call. Assume I want to check if my hardware supports AVX or not, I can check it as below:

#include<stdio.h>

int main(){
    if(__builtin_cpu_supports("avx"))
        printf("AVX supported\n");
    else
        printf("AVX not supported\n");
return 0;
}

By the way, you can check check list of all the flags supported by your cpu in the file cpuinfo under proc file system too.

mayank:~> cat /proc/cpuinfo|grep -i flags
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cpuid_fault pti fsgsbase smep arat

Contents For References Series

References Series:

  1. References in C++

References in C++

Starting from this post we will talk about lvalue references, pointers, rvalue references, move semantics etc.

This is first post in this series. You will find all the post of this series here.

This post will talk just about references (lvalue references to be precise). But if you don’t understand how lvalue references differ from rvalue references don’t worry we will try to understand all these jargons in this series.

What is meant by references?

A reference defines an alternative name for an object. A reference type ‘refers to’ another type. Reference is like an alias for another variable.

Defining a reference

int a = 10;
int &refA = a;

In above snippet we bound a reference refA to integer variable a. In other words, refA is alias for a.

Few important points to remember

  1. A reference is not an object. Reference, is just another name for an object.
  2. It is necessary to initialize references.
  3. There’s no way to rebind references. Once bound a reference remains bound to its initial object.
  4. All the operations on a reference are actually on object to which reference is bound.
  5. With few expections the type of reference should match the type of object to which reference is bound.
  6. As references are not objects so we can’t define reference to a reference.

Let’s try to understand all above points in detail.

A reference is not an object. Reference, is just another name for an object.

Not much to say here. Just don’t think of references as object.

It is necessary to initialize references.

Initializing a reference is necessary.

int a = 10;
int &refA;     // Error

int &refA; is illegal, as we have not initialized the reference named refA.

There’s no way to rebind references. Once bound a reference remains bound to its initial object.

References reamins bounded to the object which it was initialized with, through out the life of reference.

From Point 2 and 3 we can conclude that references can’t be bound to NULL as intialization of references is necessary and also we can’t rebind them. So there’s no way of binding reference to NULL.

Let’s consider below example to understand why reference re-binding is ambigous.

int a = 10;
int b = 20;
int &refA = a;
refA = b;

Now assume that we allowed references to rebound. In this case refA = b in above code snippet can mean one of below two:

  • Rebound reference refA to b.
  • Change the value of object pointed by refA, which is a to 20.

So it would be quite ambigous if rebinding references would have been allowed. So in C++ statement refA = b would mean that value of a is change to 20.

All the operations on a reference are actually on object to which reference is bound.

#include<iostream>

int main(){
   int a =10;
   int b = 20;
   int &refA = a;
   int &refB = b;
   std::cout << refA + refB ; //Ouput : 30
}

Adding refA and refB actually performs operation on a and b. When we assign to a reference, we are assigning to the object to which the reference is bound. When we fetch the value of a reference, we are really fetching the value of the object to which the reference is bound. Similarly, when we use a reference as an initializer, we are really using the object to which the reference is bound.

With few expections the type of reference should match the type of object to which reference is bound.

float a =10;
int &refA = a;

We define a of type float, but we are trying to bind this object to reference of type int. This is not allowed.

NOTE: We will talk about exception which is mentioned here in later post.

As references are not objects so we can’t define reference to a reference.

Just as we define pointers to pointers we can’t define references to references.

This was about basics of reference. We will continue this series in next blog post.

Till then Sayonara.

Thanks.

Mutable lambdas in C++

This post is in continuation to Lambdas in C++.

Till now we covered basics of functors and lambdas in C++. We will cover Mutable lambdas in this post.

Mutable Lambdas

Object captured in lambda are immutable by default. This is because operator() of the generated functor (compiler generates functional object for lambdas) is const by default. Consider below C++ code:

#include<iostream>

int main(){
   int a=10;
    auto lam = [a](){a;};
    lam();
    return 0;
}

Assembly code for lambda lam generated by gcc 4.9.4 is:

main::{lambda()#1}::operator()() const:
  push rbp
  mov rbp, rsp
  mov QWORD PTR [rbp-8], rdi
  pop rbp
  ret

As you can see that const keyword is present in generated functor of lambda main::{lambda()#1}::operator()() const. This const prevent us from modifying objects in lambda captured by value.

int a=10;
auto lam = [a](){a++;}; //Compilation error 

Using mutable keyword allows us to mutate objects captured by value too.

int a=10;
auto lam = [a]() mutable {a++;};

If we see the assembly code for same code the generated functor after adding mutable keyword looks like:

main::{lambda()#1}::operator()()

We can clearly see that const is no longer present now. So adding mutable keyword makes operator() non-const.

In general lambda declaration mutable keyword comes before return-type

auto func = [a]() mutable -> int {++a; std::cout << a; return a;};

That’s it for mutable lambdas. I think we covered basics of lambdas. We will start with R-value reference from next blog post.

Till then Sayonara.

Lambdas in C++

Lambdas vs Functors

As we saw in last post we can use STL functors for common operations like sum, divide. But at times when we need to write our own functor the amount of code needed to define functor is too much. Below is an example to show how useful and concise lambdas can be.

Using functors :

#include<iostream>
#include<vector>
#include<algorithm>

using myPair = std::pair<int,int>;
struct MyCompare{
    bool operator()(myPair p1,myPair p2){
        return p2.second > p1.second;
    }
}mycompare;

int main(){
    std::vector<myPair> records(3);

    records[0] = std::make_pair(12,10);
    records[1] = std::make_pair(2,19);
    records[2] = std::make_pair(1,12);

    std::sort(records.begin(),records.end(),mycompare);
}

Using lambdas ( >C++11 ):

#include<iostream>
#include<vector>
#include<algorithm>

int main(){
    using myPair = std::pair<int,int>;
    std::vector<myPair> records(3);

    records[0] = std::make_pair(12,10);
    records[1] = std::make_pair(2,19);
    records[2] = std::make_pair(1,12);

    std::sort(records.begin(),records.end(),
            [](myPair p1,myPair p2){return p2.second > p1.second;});
}

What is a lambda?

A lambda is syntactic sugar for writing functors. Lambda can be thought of as unnamed inline function. Like any another C++ function lambdas has parameters, return type and body. Unlike a function, lambdas may be defined inside a function.

Syntax

In general, A lambda expression looks like:

[ capture list ] ( parameter list ) -> return type { function body }

Now let’s try to understand what each entity in above definition means.

[ capture list ]

By default, variables of the enclosing scope cannot be accessed by a lambda.

int a = 10;
auto myLambda = [](){std::cout << a ;}; // ERROR
myLambda();

In above code snippet we are trying to use value of a without capturing, hence error.

The capture list specifies which outside variables are available for the lambda function and whether they should be captured by value or by reference. Capturing a variable makes it accessible inside the lambda.

Capture a by value: [a](){}

Capture a by reference: [&a](){}

When an variable is captured by value we cannot change value of the variable inside lambda.

/*
a is captured by value and we  are changing 
value of a, which is not allowed. So this is 
an error. 
*/

auto myLambda = [a](){a = a+2;} // ERROR

If we want to change value of variable in lambda we need to capture a by reference (by having & before variable name in capture list). In this case change in value of a inside lambda would be reflected outside lambda too.

int a  = 10;
/*
To change value of a in lambda we need
to capture by reference, as in below statement.
*/
auto myLambda2 = [&a](){a = a+2;} // Works!
myLambda2();
print(a); // Value of a becomes 12 outside
	      // scope of lambda2.

Few points to remember :

  • Even if there isn’t any variables to capture, having [] is mandatory. We can keep capture list empty like [] when we don’t want to capture anything.

  • Don’t confuse capture list with arguments of conventional functions. Unlike function arguments, they do not have to be passed when calling the lambda.

  • capture list captures the value of variable when lambda was defined and not at time when lambda was called.
    int a =10;
    auto myLambda = [a](){std:::cout << a;};
    a =14;
    myLambda(); // myLambda get value of a as 10 and not 14.
    
  • Variable should be defined in scope of lambda.
    auto myLambda = [a](){a = a+2;} // Error: a is not defined.
    int a =10;
    myLambda(); 
    

    ( Parameter list )

This is the optional parameters list. We can omit parentheses when we don’t need any argument to lambda (except in case when lambda is defined as mutable, we will see this later).

auto myLambda = [] { std::cout « ” Hello world”; };
// Valid. Notice we don’t have () of parameter list between capture list and function body.

return type

This is the return type of lambda. Most of the time, compilers can deduce the return type of the lambda expression when you have zero or one return statement, returning same type.

auto myLambda = [](){std::cout << "hi";}; 
          // return type is deduced as void
auto myLambda2 = [](){ if(a==2) return 2; else return 3;};
			// return type would be deduced as int
	
	

However, in case when multiple return types are of different type compiler won’t be able to deduce the return type and will thrown error.

auto myLambda3 = [](){ if(a==2) return 2; else return 3.5;}; // ERROR
		// Compiler won't be able to deduce return type of lambda
		// and hence compiler would throw error. We will need to
		// specify return type in this case. 

auto myLambda4 = []()-> double { if(a==2) return 2; else return 3.5;};
		// Works as return type is specified.
		

This post talks about syntax and some basic rules of lambdas. In next post we will talk about some more concepts in lambdas like mutable lambdas, recursive lambdas etc.

Till then, Sayonara.

Thanks,
Mayank