bitunion.hh revision 12625
14680Sgblack@eecs.umich.edu/*
25442Sgblack@eecs.umich.edu * Copyright (c) 2007-2008 The Regents of The University of Michigan
34680Sgblack@eecs.umich.edu * All rights reserved.
44680Sgblack@eecs.umich.edu *
54680Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
64680Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
74680Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
84680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
94680Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
104680Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
114680Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
124680Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
134680Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
144680Sgblack@eecs.umich.edu * this software without specific prior written permission.
154680Sgblack@eecs.umich.edu *
164680Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174680Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184680Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194680Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204680Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214680Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224680Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234680Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244680Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254680Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264680Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274680Sgblack@eecs.umich.edu *
284680Sgblack@eecs.umich.edu * Authors: Gabe Black
294680Sgblack@eecs.umich.edu */
304680Sgblack@eecs.umich.edu
314680Sgblack@eecs.umich.edu#ifndef __BASE_BITUNION_HH__
324680Sgblack@eecs.umich.edu#define __BASE_BITUNION_HH__
334680Sgblack@eecs.umich.edu
3412491Sgabeblack@google.com#include <functional>
3512625Sgabeblack@google.com#include <iostream>
3612450Sgabeblack@google.com#include <type_traits>
3712625Sgabeblack@google.com#include <typeinfo>
3812450Sgabeblack@google.com
394680Sgblack@eecs.umich.edu#include "base/bitfield.hh"
404680Sgblack@eecs.umich.edu
415543Ssaidi@eecs.umich.edu//      The following implements the BitUnion system of defining bitfields
424680Sgblack@eecs.umich.edu//on top of an underlying class. This is done through the pervasive use of
434680Sgblack@eecs.umich.edu//both named and unnamed unions which all contain the same actual storage.
444680Sgblack@eecs.umich.edu//Since they're unioned with each other, all of these storage locations
454680Sgblack@eecs.umich.edu//overlap. This allows all of the bitfields to manipulate the same data
464680Sgblack@eecs.umich.edu//without having to have access to each other. More details are provided with
474680Sgblack@eecs.umich.edu//the individual components.
484680Sgblack@eecs.umich.edu
4912450Sgabeblack@google.com//This class wraps around another which defines getter/setter functions which
5012450Sgabeblack@google.com//manipulate the underlying data. The type of the underlying data and the type
5112450Sgabeblack@google.com//of the bitfield itself are inferred from the argument types of the setter
5212450Sgabeblack@google.com//function.
5312450Sgabeblack@google.comtemplate<class Base>
5412450Sgabeblack@google.comclass BitfieldTypeImpl : public Base
5512450Sgabeblack@google.com{
5612450Sgabeblack@google.com    static_assert(std::is_empty<Base>::value,
5712450Sgabeblack@google.com                  "Bitfield base class must be empty.");
5812450Sgabeblack@google.com
5912450Sgabeblack@google.com  private:
6012450Sgabeblack@google.com
6112465Sgabeblack@google.com    struct TypeDeducer
6212465Sgabeblack@google.com    {
6312465Sgabeblack@google.com        template<typename>
6412465Sgabeblack@google.com        struct T;
6512450Sgabeblack@google.com
6612465Sgabeblack@google.com        template<typename C, typename Type1, typename Type2>
6712465Sgabeblack@google.com        struct T<void (C::*)(Type1 &, Type2)>
6812465Sgabeblack@google.com        {
6912465Sgabeblack@google.com            typedef Type1 Storage;
7012465Sgabeblack@google.com            typedef Type2 Type;
7112465Sgabeblack@google.com        };
7212450Sgabeblack@google.com
7312465Sgabeblack@google.com        struct Wrapper : public Base
7412465Sgabeblack@google.com        {
7512465Sgabeblack@google.com            using Base::setter;
7612465Sgabeblack@google.com        };
7712465Sgabeblack@google.com
7812465Sgabeblack@google.com        typedef typename T<decltype(&Wrapper::setter)>::Storage Storage;
7912465Sgabeblack@google.com        typedef typename T<decltype(&Wrapper::setter)>::Type Type;
8012450Sgabeblack@google.com    };
8112450Sgabeblack@google.com
8212450Sgabeblack@google.com  protected:
8312465Sgabeblack@google.com    typedef typename TypeDeducer::Storage Storage;
8412465Sgabeblack@google.com    typedef typename TypeDeducer::Type Type;
8512450Sgabeblack@google.com
8612450Sgabeblack@google.com    Type getter(const Storage &storage) const = delete;
8712450Sgabeblack@google.com    void setter(Storage &storage, Type val) = delete;
8812450Sgabeblack@google.com
8912450Sgabeblack@google.com    Storage __storage;
9012450Sgabeblack@google.com
9112450Sgabeblack@google.com    operator Type () const
9212450Sgabeblack@google.com    {
9312450Sgabeblack@google.com        return Base::getter(__storage);
9412450Sgabeblack@google.com    }
9512450Sgabeblack@google.com
9612450Sgabeblack@google.com    Type
9712450Sgabeblack@google.com    operator=(const Type val)
9812450Sgabeblack@google.com    {
9912450Sgabeblack@google.com        Base::setter(__storage, val);
10012450Sgabeblack@google.com        return val;
10112450Sgabeblack@google.com    }
10212450Sgabeblack@google.com
10312450Sgabeblack@google.com    Type
10412450Sgabeblack@google.com    operator=(BitfieldTypeImpl<Base> const & other)
10512450Sgabeblack@google.com    {
10612450Sgabeblack@google.com        return *this = (Type)other;
10712450Sgabeblack@google.com    }
10812450Sgabeblack@google.com};
10912450Sgabeblack@google.com
11012450Sgabeblack@google.com//A wrapper for the above class which allows setting and getting.
11112450Sgabeblack@google.comtemplate<class Base>
11212450Sgabeblack@google.comclass BitfieldType : public BitfieldTypeImpl<Base>
11312450Sgabeblack@google.com{
11412450Sgabeblack@google.com  protected:
11512450Sgabeblack@google.com    using Impl = BitfieldTypeImpl<Base>;
11612450Sgabeblack@google.com    using typename Impl::Type;
11712450Sgabeblack@google.com
11812450Sgabeblack@google.com  public:
11912450Sgabeblack@google.com    operator Type () const { return Impl::operator Type(); }
12012450Sgabeblack@google.com    Type operator=(const Type val) { return Impl::operator=(val); }
12112450Sgabeblack@google.com    Type
12212450Sgabeblack@google.com    operator=(BitfieldType<Base> const & other)
12312450Sgabeblack@google.com    {
12412450Sgabeblack@google.com        return Impl::operator=(other);
12512450Sgabeblack@google.com    }
12612450Sgabeblack@google.com};
12712450Sgabeblack@google.com
12812450Sgabeblack@google.com//A wrapper which only supports getting.
12912450Sgabeblack@google.comtemplate<class Base>
13012450Sgabeblack@google.comclass BitfieldROType : public BitfieldTypeImpl<Base>
13112450Sgabeblack@google.com{
13212450Sgabeblack@google.com  public:
13312450Sgabeblack@google.com    using Impl = BitfieldTypeImpl<Base>;
13412450Sgabeblack@google.com    using typename Impl::Type;
13512450Sgabeblack@google.com
13612450Sgabeblack@google.com    Type operator=(BitfieldROType<Base> const &other) = delete;
13712450Sgabeblack@google.com    operator Type () const { return Impl::operator Type(); }
13812450Sgabeblack@google.com};
13912450Sgabeblack@google.com
14012450Sgabeblack@google.com//A wrapper which only supports setting.
14112450Sgabeblack@google.comtemplate <class Base>
14212450Sgabeblack@google.comclass BitfieldWOType : public BitfieldTypeImpl<Base>
14312450Sgabeblack@google.com{
14412450Sgabeblack@google.com  protected:
14512450Sgabeblack@google.com    using Impl = BitfieldTypeImpl<Base>;
14612450Sgabeblack@google.com    using typename Impl::Type;
14712450Sgabeblack@google.com
14812450Sgabeblack@google.com  public:
14912450Sgabeblack@google.com    Type operator=(const Type val) { return Impl::operator=(val); }
15012450Sgabeblack@google.com    Type
15112450Sgabeblack@google.com    operator=(BitfieldWOType<Base> const & other)
15212450Sgabeblack@google.com    {
15312450Sgabeblack@google.com        return Impl::operator=(other);
15412450Sgabeblack@google.com    }
15512450Sgabeblack@google.com};
15612450Sgabeblack@google.com
1574680Sgblack@eecs.umich.edu//This namespace is for classes which implement the backend of the BitUnion
15812450Sgabeblack@google.com//stuff. Don't use any of these directly.
1594680Sgblack@eecs.umich.edunamespace BitfieldBackend
1604680Sgblack@eecs.umich.edu{
16112450Sgabeblack@google.com    template<class Storage, int first, int last>
16212450Sgabeblack@google.com    class Unsigned
1634680Sgblack@eecs.umich.edu    {
16412450Sgabeblack@google.com        static_assert(first >= last,
16512450Sgabeblack@google.com                      "Bitfield ranges must be specified as <msb, lsb>");
16612450Sgabeblack@google.com
1674680Sgblack@eecs.umich.edu      protected:
16812450Sgabeblack@google.com        uint64_t
16912450Sgabeblack@google.com        getter(const Storage &storage) const
1704680Sgblack@eecs.umich.edu        {
17112450Sgabeblack@google.com            return bits(storage, first, last);
1724680Sgblack@eecs.umich.edu        }
1734680Sgblack@eecs.umich.edu
17412450Sgabeblack@google.com        void
17512450Sgabeblack@google.com        setter(Storage &storage, uint64_t val)
1764680Sgblack@eecs.umich.edu        {
17712450Sgabeblack@google.com            replaceBits(storage, first, last, val);
1784680Sgblack@eecs.umich.edu        }
1794680Sgblack@eecs.umich.edu    };
1804680Sgblack@eecs.umich.edu
18112450Sgabeblack@google.com    template<class Storage, int first, int last>
18212450Sgabeblack@google.com    class Signed
18312450Sgabeblack@google.com    {
18412450Sgabeblack@google.com        static_assert(first >= last,
18512450Sgabeblack@google.com                      "Bitfield ranges must be specified as <msb, lsb>");
18612450Sgabeblack@google.com
18712450Sgabeblack@google.com      protected:
18812450Sgabeblack@google.com        int64_t
18912450Sgabeblack@google.com        getter(const Storage &storage) const
19012450Sgabeblack@google.com        {
19112450Sgabeblack@google.com            return sext<first - last + 1>(bits(storage, first, last));
19212450Sgabeblack@google.com        }
19312450Sgabeblack@google.com
19412450Sgabeblack@google.com        void
19512450Sgabeblack@google.com        setter(Storage &storage, int64_t val)
19612450Sgabeblack@google.com        {
19712450Sgabeblack@google.com            replaceBits(storage, first, last, val);
19812450Sgabeblack@google.com        }
19912450Sgabeblack@google.com    };
20012450Sgabeblack@google.com
20112450Sgabeblack@google.com    //This class contains the basic bitfield types which are automatically
20212450Sgabeblack@google.com    //available within a BitUnion. They inherit their Storage type from the
20312450Sgabeblack@google.com    //containing BitUnion.
20412450Sgabeblack@google.com    template<class Storage>
20512450Sgabeblack@google.com    class BitfieldTypes
2064680Sgblack@eecs.umich.edu    {
2074680Sgblack@eecs.umich.edu      protected:
20812450Sgabeblack@google.com
2094680Sgblack@eecs.umich.edu        template<int first, int last=first>
21012450Sgabeblack@google.com        using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
21112450Sgabeblack@google.com        template<int first, int last=first>
21212450Sgabeblack@google.com        using BitfieldRO =
21312450Sgabeblack@google.com                BitfieldROType<Unsigned<Storage, first, last> >;
21412450Sgabeblack@google.com        template<int first, int last=first>
21512450Sgabeblack@google.com        using BitfieldWO =
21612450Sgabeblack@google.com                BitfieldWOType<Unsigned<Storage, first, last> >;
21710289SAndreas.Sandberg@ARM.com
2184680Sgblack@eecs.umich.edu        template<int first, int last=first>
21912450Sgabeblack@google.com        using SignedBitfield =
22012450Sgabeblack@google.com                BitfieldType<Signed<Storage, first, last> >;
2214680Sgblack@eecs.umich.edu        template<int first, int last=first>
22212450Sgabeblack@google.com        using SignedBitfieldRO =
22312450Sgabeblack@google.com                BitfieldROType<Signed<Storage, first, last> >;
22412450Sgabeblack@google.com        template<int first, int last=first>
22512450Sgabeblack@google.com        using SignedBitfieldWO =
22612450Sgabeblack@google.com                BitfieldWOType<Signed<Storage, first, last> >;
2274680Sgblack@eecs.umich.edu    };
2284680Sgblack@eecs.umich.edu
2294680Sgblack@eecs.umich.edu    //When a BitUnion is set up, an underlying class is created which holds
2304680Sgblack@eecs.umich.edu    //the actual union. This class then inherits from it, and provids the
2314680Sgblack@eecs.umich.edu    //implementations for various operators. Setting things up this way
2324680Sgblack@eecs.umich.edu    //prevents having to redefine these functions in every different BitUnion
2334680Sgblack@eecs.umich.edu    //type. More operators could be implemented in the future, as the need
2344680Sgblack@eecs.umich.edu    //arises.
23512450Sgabeblack@google.com    template <class Base>
2364680Sgblack@eecs.umich.edu    class BitUnionOperators : public Base
2374680Sgblack@eecs.umich.edu    {
23812450Sgabeblack@google.com        static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
23912450Sgabeblack@google.com                      "BitUnion larger than its storage type.");
24012450Sgabeblack@google.com
2414680Sgblack@eecs.umich.edu      public:
24212450Sgabeblack@google.com        BitUnionOperators(typename Base::__StorageType const &val)
2434681Sgblack@eecs.umich.edu        {
24412450Sgabeblack@google.com            Base::__storage = val;
2454681Sgblack@eecs.umich.edu        }
2464681Sgblack@eecs.umich.edu
2474681Sgblack@eecs.umich.edu        BitUnionOperators() {}
2484681Sgblack@eecs.umich.edu
24912450Sgabeblack@google.com        operator const typename Base::__StorageType () const
2504680Sgblack@eecs.umich.edu        {
25112450Sgabeblack@google.com            return Base::__storage;
2524680Sgblack@eecs.umich.edu        }
2534680Sgblack@eecs.umich.edu
25412450Sgabeblack@google.com        typename Base::__StorageType
25512450Sgabeblack@google.com        operator=(typename Base::__StorageType const &val)
2564680Sgblack@eecs.umich.edu        {
25712450Sgabeblack@google.com            Base::__storage = val;
25812450Sgabeblack@google.com            return val;
2594680Sgblack@eecs.umich.edu        }
2604680Sgblack@eecs.umich.edu
26112450Sgabeblack@google.com        typename Base::__StorageType
26212450Sgabeblack@google.com        operator=(BitUnionOperators const &other)
26310640Sgabeblack@google.com        {
26412450Sgabeblack@google.com            Base::__storage = other;
26512450Sgabeblack@google.com            return Base::__storage;
26610640Sgabeblack@google.com        }
26710640Sgabeblack@google.com
2684680Sgblack@eecs.umich.edu        bool
26912450Sgabeblack@google.com        operator<(Base const &base) const
2704680Sgblack@eecs.umich.edu        {
27112450Sgabeblack@google.com            return Base::__storage < base.__storage;
2724680Sgblack@eecs.umich.edu        }
2734680Sgblack@eecs.umich.edu
2744680Sgblack@eecs.umich.edu        bool
27512450Sgabeblack@google.com        operator==(Base const &base) const
2764680Sgblack@eecs.umich.edu        {
27712450Sgabeblack@google.com            return Base::__storage == base.__storage;
2784680Sgblack@eecs.umich.edu        }
2794680Sgblack@eecs.umich.edu    };
2804680Sgblack@eecs.umich.edu}
2814680Sgblack@eecs.umich.edu
2824680Sgblack@eecs.umich.edu//This macro is a backend for other macros that specialize it slightly.
2834680Sgblack@eecs.umich.edu//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
2844680Sgblack@eecs.umich.edu//sticks the class which has the actual union in it, which
2854680Sgblack@eecs.umich.edu//BitfieldOperators above inherits from. Putting these classes in a special
2864680Sgblack@eecs.umich.edu//namespace ensures that there will be no collisions with other names as long
2874680Sgblack@eecs.umich.edu//as the BitUnion names themselves are all distinct and nothing else uses
2884680Sgblack@eecs.umich.edu//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
28912450Sgabeblack@google.com//creates a typedef of the "type" parameter called __StorageType. This allows
2904680Sgblack@eecs.umich.edu//the type to propagate outside of the macro itself in a controlled way.
2914680Sgblack@eecs.umich.edu//Finally, the base storage is defined which BitfieldOperators will refer to
2924680Sgblack@eecs.umich.edu//in the operators it defines. This macro is intended to be followed by
2934680Sgblack@eecs.umich.edu//bitfield definitions which will end up inside it's union. As explained
29412450Sgabeblack@google.com//above, these is overlayed the __storage member in its entirety by each of the
2954680Sgblack@eecs.umich.edu//bitfields which are defined in the union, creating shared storage with no
2964680Sgblack@eecs.umich.edu//overhead.
2974680Sgblack@eecs.umich.edu#define __BitUnion(type, name) \
2985442Sgblack@eecs.umich.edu    class BitfieldUnderlyingClasses##name : \
2994680Sgblack@eecs.umich.edu        public BitfieldBackend::BitfieldTypes<type> \
3004680Sgblack@eecs.umich.edu    { \
30112454Sgabeblack@google.com      protected: \
30212454Sgabeblack@google.com        typedef type __StorageType; \
30312454Sgabeblack@google.com        friend BitfieldBackend::BitUnionBaseType< \
30412454Sgabeblack@google.com            BitfieldBackend::BitUnionOperators< \
30512454Sgabeblack@google.com                BitfieldUnderlyingClasses##name> >; \
30612454Sgabeblack@google.com        friend BitfieldBackend::BitUnionBaseType< \
30712454Sgabeblack@google.com                BitfieldUnderlyingClasses##name>; \
3084680Sgblack@eecs.umich.edu      public: \
3094680Sgblack@eecs.umich.edu        union { \
31012450Sgabeblack@google.com            type __storage;
3114680Sgblack@eecs.umich.edu
3124680Sgblack@eecs.umich.edu//This closes off the class and union started by the above macro. It is
3134680Sgblack@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator
3144680Sgblack@eecs.umich.edu//class inheriting from the class and union just defined, which completes
3154680Sgblack@eecs.umich.edu//building up the type for the user.
3164680Sgblack@eecs.umich.edu#define EndBitUnion(name) \
3174680Sgblack@eecs.umich.edu        }; \
3184680Sgblack@eecs.umich.edu    }; \
3194680Sgblack@eecs.umich.edu    typedef BitfieldBackend::BitUnionOperators< \
3205442Sgblack@eecs.umich.edu        BitfieldUnderlyingClasses##name> name;
3214680Sgblack@eecs.umich.edu
3224680Sgblack@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The
32312450Sgabeblack@google.com//__storage member functions like the "underlying storage" of the top level
3244680Sgblack@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so
3254680Sgblack@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a
3264680Sgblack@eecs.umich.edu//regular bitfield when referred to by itself.
32712450Sgabeblack@google.com#define __SubBitUnion(name, fieldType, ...) \
32812450Sgabeblack@google.com    class \
3294680Sgblack@eecs.umich.edu    { \
3304680Sgblack@eecs.umich.edu      public: \
3314680Sgblack@eecs.umich.edu        union { \
33212450Sgabeblack@google.com            fieldType<__VA_ARGS__> __storage;
3334680Sgblack@eecs.umich.edu
3344680Sgblack@eecs.umich.edu//This closes off the union created above and gives it a name. Unlike the top
3354680Sgblack@eecs.umich.edu//level BitUnion, we're interested in creating an object instead of a type.
3364680Sgblack@eecs.umich.edu//The operators are defined in the macro itself instead of a class for
3374680Sgblack@eecs.umich.edu//technical reasons. If someone determines a way to move them to one, please
3384680Sgblack@eecs.umich.edu//do so.
3394680Sgblack@eecs.umich.edu#define EndSubBitUnion(name) \
3404680Sgblack@eecs.umich.edu        }; \
34112450Sgabeblack@google.com        inline operator __StorageType () const \
34212450Sgabeblack@google.com        { return __storage; } \
3434680Sgblack@eecs.umich.edu        \
34412450Sgabeblack@google.com        inline __StorageType operator = (const __StorageType & _storage) \
34512450Sgabeblack@google.com        { return __storage = _storage;} \
3464680Sgblack@eecs.umich.edu    } name;
3474680Sgblack@eecs.umich.edu
3484680Sgblack@eecs.umich.edu//Regular bitfields
3494680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
3504680Sgblack@eecs.umich.edu#define SubBitUnion(name, first, last) \
35112450Sgabeblack@google.com    __SubBitUnion(name, Bitfield, first, last)
3524680Sgblack@eecs.umich.edu
3534680Sgblack@eecs.umich.edu//Regular bitfields
3544680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
3554680Sgblack@eecs.umich.edu#define SignedSubBitUnion(name, first, last) \
35612450Sgabeblack@google.com    __SubBitUnion(name, SignedBitfield, first, last)
3574680Sgblack@eecs.umich.edu
3584680Sgblack@eecs.umich.edu//Use this to define an arbitrary type overlayed with bitfields.
3594680Sgblack@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name)
3604680Sgblack@eecs.umich.edu
3614680Sgblack@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields.
3624680Sgblack@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name)
3634680Sgblack@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name)
3644680Sgblack@eecs.umich.edu#define BitUnion16(name) __BitUnion(uint16_t, name)
3654680Sgblack@eecs.umich.edu#define BitUnion8(name) __BitUnion(uint8_t, name)
3664680Sgblack@eecs.umich.edu
36712451Sgabeblack@google.com
36812451Sgabeblack@google.com//These templates make it possible to define other templates related to
36912451Sgabeblack@google.com//BitUnions without having to refer to internal typedefs or the BitfieldBackend
37012451Sgabeblack@google.com//namespace.
37112451Sgabeblack@google.com
37212451Sgabeblack@google.com//To build a template specialization which works for all BitUnions, accept a
37312451Sgabeblack@google.com//template argument T, and then use BitUnionType<T> as an argument in the
37412451Sgabeblack@google.com//template. To refer to the basic type the BitUnion wraps, use
37512451Sgabeblack@google.com//BitUnionBaseType<T>.
37612451Sgabeblack@google.com
37712451Sgabeblack@google.com//For example:
37812451Sgabeblack@google.com//template <typename T>
37912451Sgabeblack@google.com//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
38012451Sgabeblack@google.com
38112451Sgabeblack@google.com//Also, BitUnionBaseType can be used on a BitUnion type directly.
38212451Sgabeblack@google.com
38312451Sgabeblack@google.comtemplate <typename T>
38412451Sgabeblack@google.comusing BitUnionType = BitfieldBackend::BitUnionOperators<T>;
38512451Sgabeblack@google.com
38612451Sgabeblack@google.comnamespace BitfieldBackend
38712451Sgabeblack@google.com{
38812451Sgabeblack@google.com    template<typename T>
38912451Sgabeblack@google.com    struct BitUnionBaseType
39012451Sgabeblack@google.com    {
39112451Sgabeblack@google.com        typedef typename BitUnionType<T>::__StorageType Type;
39212451Sgabeblack@google.com    };
39312451Sgabeblack@google.com
39412451Sgabeblack@google.com    template<typename T>
39512451Sgabeblack@google.com    struct BitUnionBaseType<BitUnionType<T> >
39612451Sgabeblack@google.com    {
39712451Sgabeblack@google.com        typedef typename BitUnionType<T>::__StorageType Type;
39812451Sgabeblack@google.com    };
39912451Sgabeblack@google.com}
40012451Sgabeblack@google.com
40112451Sgabeblack@google.comtemplate <typename T>
40212451Sgabeblack@google.comusing BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
40312451Sgabeblack@google.com
40412454Sgabeblack@google.com
40512454Sgabeblack@google.com//An STL style hash structure for hashing BitUnions based on their base type.
40612453Sgabeblack@google.comnamespace std
40712453Sgabeblack@google.com{
40812453Sgabeblack@google.com    template <typename T>
40912453Sgabeblack@google.com    struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> >
41012453Sgabeblack@google.com    {
41112453Sgabeblack@google.com        size_t
41212453Sgabeblack@google.com        operator() (const BitUnionType<T> &val) const
41312453Sgabeblack@google.com        {
41412453Sgabeblack@google.com            return hash<BitUnionBaseType<T> >::operator()(val);
41512453Sgabeblack@google.com        }
41612453Sgabeblack@google.com    };
41712453Sgabeblack@google.com}
41812453Sgabeblack@google.com
41912625Sgabeblack@google.com
42012625Sgabeblack@google.comnamespace BitfieldBackend
42112625Sgabeblack@google.com{
42212625Sgabeblack@google.comnamespace
42312625Sgabeblack@google.com{
42412625Sgabeblack@google.com    template<typename T>
42512625Sgabeblack@google.com    std::ostream &
42612625Sgabeblack@google.com    bitfieldBackendPrinter(std::ostream &os, const T &t)
42712625Sgabeblack@google.com    {
42812625Sgabeblack@google.com        os << t;
42912625Sgabeblack@google.com        return os;
43012625Sgabeblack@google.com    }
43112625Sgabeblack@google.com
43212625Sgabeblack@google.com    //Since BitUnions are generally numerical values and not character codes,
43312625Sgabeblack@google.com    //these specializations attempt to ensure that they get cast to integers
43412625Sgabeblack@google.com    //of the appropriate type before printing.
43512625Sgabeblack@google.com    template <>
43612625Sgabeblack@google.com    std::ostream &
43712625Sgabeblack@google.com    bitfieldBackendPrinter(std::ostream &os, const char &t)
43812625Sgabeblack@google.com    {
43912625Sgabeblack@google.com        os << (const int)t;
44012625Sgabeblack@google.com        return os;
44112625Sgabeblack@google.com    }
44212625Sgabeblack@google.com
44312625Sgabeblack@google.com    template <>
44412625Sgabeblack@google.com    std::ostream &
44512625Sgabeblack@google.com    bitfieldBackendPrinter(std::ostream &os, const unsigned char &t)
44612625Sgabeblack@google.com    {
44712625Sgabeblack@google.com        os << (const unsigned int)t;
44812625Sgabeblack@google.com        return os;
44912625Sgabeblack@google.com    }
45012625Sgabeblack@google.com}
45112625Sgabeblack@google.com}
45212625Sgabeblack@google.com
45312625Sgabeblack@google.com//A default << operator which casts a bitunion to its underlying type and
45412625Sgabeblack@google.com//passes it to BitfieldBackend::bitfieldBackendPrinter.
45512625Sgabeblack@google.comtemplate <typename T>
45612625Sgabeblack@google.comstd::ostream &
45712625Sgabeblack@google.comoperator << (std::ostream &os, const BitUnionType<T> &bu)
45812625Sgabeblack@google.com{
45912625Sgabeblack@google.com    return BitfieldBackend::bitfieldBackendPrinter(
46012625Sgabeblack@google.com            os, (BitUnionBaseType<T>)bu);
46112625Sgabeblack@google.com}
46212625Sgabeblack@google.com
4634680Sgblack@eecs.umich.edu#endif // __BASE_BITUNION_HH__
464