/**************************************************************************\

MODULE: vec_GF2

SUMMARY:


The class Vec<GF2> is explicitly specialized.  It behaves much like a generic
Vec<T> (see vector.txt), but there are some differences.

For efficiency, elements of a Vec<GF2> are "packed" into a word.  You can still
use subscript notation v[i] or v(i).  For const vectors, these evaluate to
values of type const GF2.  For non-const vectors, these evaluate to values of
the special type ref_GF2, which is defined in the GF2 header file.

There are implicit conversions from ref_GF2 to const GF2 and from GF2& to
ref_GF2.  Therefore, if you want to declare a function that takes a non-const
reference to a GF2, you should declare the parameter of type ref_GF2: this will
allow you to pass variables of type GF2 as well as elements of vec_GF2's
obtained through indexing.

As an alternative, one can use the get and put methods below to access
vector elements.

There is a subtle but important difference in the semantics of Vec<GF2> and
that of generic NTL vectors.  With a Vec<GF2>, whenever its length is increased
(via SetLength), the "new" bits are always 0.  For example, if 
v.length() == 20, then 

   v.SetLength(10); v.setLength(20);

will effectively clear bits 10..19 of v.  This is quite different from the
semantics of generic NTL vectors, where the above sequence would not change the
value of v at all.  One has to be aware of this difference, but it will not
matter in most ordinary circumstances.


Another thing to be aware of is the use of Vec<GF2> in range-based
for loops.  The safest ways to do this are as follows:

   for (auto&& item : vec) { ... } // for read-only or read/write access

or

   for (GF2 item : vec) { ... } // for access via a copy

Note that:
   * declaring item as "auto&" or "GF2&" will yield a syntax error
   * declaring item as "auto" or "const auto&" will potentially
     allow code to modify vec via item, without a warning or error,
     contrary to expectations (although this cannot happen if vec
     itself is const)

However, declaring item as "auto&&" will work as expected, and the compiler
will raise an error if you try to modify a const Vec<GF2>.  

All of these issues arise because ref_GF2 is not a true reference, and the
semantics of "auto" and "auto&" interact badly.  Similar issues arise with
vector<bool> in the STL.

\**************************************************************************/



template<>
class Vec<GF2> {

public:

   Vec(); // 0 length vector
   Vec(INIT_SIZE_TYPE, long n); // initialize to length n
                                // usage: Vec(INIT_SIZE, n)

   Vec(const Vec<GF2>& a); // copy constructor
   Vec& operator=(const Vec<GF2>& a); // assignment

   Vec(Vec&& a);
   // move constructor (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
   // will revert to copy constructor if a is fixed

#ifndef NTL_DISABLE_MOVE_ASSIGN
   Vec& operator=(Vec&& a);
   // move assignment (C++11 only)
   // declared noexcept unless NTL_EXCEPTIONS flag is set
   // will revert to copy assignment if *this or a is fixed
#endif

   ~Vec(); // destructor



   void SetLength(long n); // set length to n bits
   void SetLength(long n, GF2 a);
      // set length to n, if length increases, initialize new bits to a

   void SetMaxLength(long n); // allocate space for n bits

   long length() const; // current length, in bits

   long MaxLength() const; // maximum length, i.e., the maximum
                           // value passed to either SetLength or SetMaxLength
                           // since creation or last kill

   long allocated() const; // number of bits for which space is allocated;
                           // if n <= v.allocated(), then v.SetLength(n)
                           // will not result in any memory re-allocation.

   // INVARIANT: 
   //    length() <= MaxLength() <= allocated() < 2^(NTL_BITS_PER_LONG-4)


   void FixLength(long n); // fix length to n bits
   // can only be applied after default initialization or kill


   void FixAtCurrentLength();
   // fixes the length at the cuurent length and prohibits
   // all future length changes.  

   // It is required that length() == MaxLength() when called.

   // EXCEPTIONS: if length() != MaxLength() and error is raised;
   // Strong ES.


   long fixed() const; // test if length has been fixed

   void kill(); // free space and make length 0

   const GF2 get(long i) const; // fetch value at index i (indexing from 0)

   void put(long i, GF2 a); // write value a to index i (indexing from 0)
   void put(long i, long a);

// Here are the subscripting operators, defined using the
// "helper" class ref_GF2

   ref_GF2 operator[](long i);
   ref_GF2 operator()(long i);

   const GF2 operator[](long i) const;
   const GF2 operator()(long i) const;


   void swap(Vec<GF2>& y);
   // swap with y (fast: just swaps pointers)

   void move(Vec<GF2>& y);
   // move y to *this (fast: just moves pointers)

   void append(GF2 a);
   // append a to end of vector

   void append(const Vec<GF2>& w);
   // append w to end of vector


// Some partial STL compatibility...also used
// to interface with the Matrix template class

   typedef GF2 value_type;
   typedef ref_GF2 reference;
   typedef const GF2 const_reference;
   typedef /* implementation defined type */ iterator;
   typedef /* implementation defined type */ const_iterator;

   ref_GF2 at(long i);
   const GF2 at(long i) const;
   // indexing with range checking


   iterator begin();
   const_iterator begin() const;
   // pointer to beginning of vector

   iterator end();
   const_iterator end() const;
   // pointer to (one past) end of vector

   // NOTES: The iterator types act like pointers.  You can perform all the
   // usual arithmetic on them, as well as dereferencing and subscripting.
   // Dereferencing an iterator yields a ref_GF2.  Dereferencing a
   // const_iterator yields a const GF2.


};



void swap(Vec<GF2>& x, Vec<GF2>& y);
// swap x and y (fast pointer swap)

void append(Vec<GF2>& v, GF2 a);
// append a to v

void append(Vec<GF2>& v, const Vec<GF2>& a);
// append a to v

// equality operators:

long operator==(const Vec<GF2>& a, const Vec<GF2>& b);
long operator!=(const Vec<GF2>& a, const Vec<GF2>& b);


// I/O operators:

ostream& operator<<(ostream& s, const Vec<GF2>& a);
istream& operator>>(istream& s, Vec<GF2>& a);

// The I/O format is [a_0 a_1 ... a_{n-1}], where each a_i is "0" or "1".
// On input, the a_i may be arbitrary integers, which are reduced mod 2.



typedef Vec<GF2> vec_GF2;  // backward compatibility

// utility routines:

void clear(vec_GF2& x); // clear all bits--length unchanged
long IsZero(const vec_GF2& a); // test if all bits are zero

void shift(vec_GF2& x, const vec_GF2& a, long n);
vec_GF2 shift(const vec_GF2& a, long n);
// x = a shifted n places, where n may be positive or negative.
// Generally, x[i] = a[i-n], so positive n shifts to a higher index.
// The length of x is set to the length of a, and bits 
// are zero-filled or discarded as necessary.

void reverse(vec_GF2& x, const vec_GF2& a); // c = a reversed
vec_GF2 reverse(const vec_GF2& a);

long weight(const vec_GF2& a); // return number of 1 bits in a


// arithmetic operations over GF(2):

void add(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
void sub(vec_GF2& x, const vec_GF2& a, const vec_GF2& b);
void negate(vec_GF2& x, const vec_GF2& a);

void mul(vec_GF2& x, const vec_GF2& a, GF2 b);
void mul(vec_GF2& x, const vec_GF2& a, long b);

void mul(vec_GF2& x, GF2 a, const vec_GF2& b);
void mul(vec_GF2& x, long a, const vec_GF2& b);
// x = a * b

void InnerProduct(ref_GF2 x, const vec_GF2& a, const vec_GF2& b);
// vectors may differ in length

void VectorCopy(vec_GF2& x, const vec_GF2& a, long n);
vec_GF2 VectorCopy(const vec_GF2& a, long n);
// x = a copy of a of length exactly n.
// The input is truncated or padded with zeroes, as necessary.

void random(vec_GF2& x, long n);  // x = random vector of length n
vec_GF2 random_vec_GF2(long n);



// arithmetic operator notation:

vec_GF2 operator+(const vec_GF2& a, const vec_GF2& b);
vec_GF2 operator-(const vec_GF2& a, const vec_GF2& b);
vec_GF2 operator-(const vec_GF2& a);

// scalar mul:

vec_GF2 operator*(const vec_GF2& a, GF2 b);
vec_GF2 operator*(const vec_GF2& a, long b);

vec_GF2 operator*(GF2 a, const vec_GF2& b);
vec_GF2 operator*(long a, const vec_GF2& b);

// inner product: 

inline GF2 operator*(const vec_GF2& a, const vec_GF2& b);

// assignment operator notation:

vec_GF2& operator+=(vec_GF2& x, const vec_GF2& a);
vec_GF2& operator-=(vec_GF2& x, const vec_GF2& a);

vec_GF2& operator*=(vec_GF2& x, GF2 a);
vec_GF2& operator*=(vec_GF2& x, long a);