bitunion.hh revision 12453
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
3412450Sgabeblack@google.com#include <iostream>
3512450Sgabeblack@google.com#include <type_traits>
3612450Sgabeblack@google.com
374680Sgblack@eecs.umich.edu#include "base/bitfield.hh"
384680Sgblack@eecs.umich.edu
395543Ssaidi@eecs.umich.edu//      The following implements the BitUnion system of defining bitfields
404680Sgblack@eecs.umich.edu//on top of an underlying class. This is done through the pervasive use of
414680Sgblack@eecs.umich.edu//both named and unnamed unions which all contain the same actual storage.
424680Sgblack@eecs.umich.edu//Since they're unioned with each other, all of these storage locations
434680Sgblack@eecs.umich.edu//overlap. This allows all of the bitfields to manipulate the same data
444680Sgblack@eecs.umich.edu//without having to have access to each other. More details are provided with
454680Sgblack@eecs.umich.edu//the individual components.
464680Sgblack@eecs.umich.edu
4712450Sgabeblack@google.com//This class wraps around another which defines getter/setter functions which
4812450Sgabeblack@google.com//manipulate the underlying data. The type of the underlying data and the type
4912450Sgabeblack@google.com//of the bitfield itself are inferred from the argument types of the setter
5012450Sgabeblack@google.com//function.
5112450Sgabeblack@google.comtemplate<class Base>
5212450Sgabeblack@google.comclass BitfieldTypeImpl : public Base
5312450Sgabeblack@google.com{
5412450Sgabeblack@google.com    static_assert(std::is_empty<Base>::value,
5512450Sgabeblack@google.com                  "Bitfield base class must be empty.");
5612450Sgabeblack@google.com
5712450Sgabeblack@google.com  private:
5812450Sgabeblack@google.com    using Base::setter;
5912450Sgabeblack@google.com
6012450Sgabeblack@google.com    template<typename T>
6112450Sgabeblack@google.com    struct TypeDeducer;
6212450Sgabeblack@google.com
6312450Sgabeblack@google.com    template<typename T>
6412450Sgabeblack@google.com    friend class TypeDeducer;
6512450Sgabeblack@google.com
6612450Sgabeblack@google.com    template<typename Type1, typename Type2>
6712450Sgabeblack@google.com    struct TypeDeducer<void (Base::*)(Type1 &, Type2)>
6812450Sgabeblack@google.com    {
6912450Sgabeblack@google.com        typedef Type1 Storage;
7012450Sgabeblack@google.com        typedef Type2 Type;
7112450Sgabeblack@google.com    };
7212450Sgabeblack@google.com
7312450Sgabeblack@google.com  protected:
7412450Sgabeblack@google.com    typedef typename TypeDeducer<
7512450Sgabeblack@google.com            decltype(&BitfieldTypeImpl<Base>::setter)>::Storage Storage;
7612450Sgabeblack@google.com    typedef typename TypeDeducer<
7712450Sgabeblack@google.com            decltype(&BitfieldTypeImpl<Base>::setter)>::Type Type;
7812450Sgabeblack@google.com
7912450Sgabeblack@google.com    Type getter(const Storage &storage) const = delete;
8012450Sgabeblack@google.com    void setter(Storage &storage, Type val) = delete;
8112450Sgabeblack@google.com
8212450Sgabeblack@google.com    Storage __storage;
8312450Sgabeblack@google.com
8412450Sgabeblack@google.com    operator Type () const
8512450Sgabeblack@google.com    {
8612450Sgabeblack@google.com        return Base::getter(__storage);
8712450Sgabeblack@google.com    }
8812450Sgabeblack@google.com
8912450Sgabeblack@google.com    Type
9012450Sgabeblack@google.com    operator=(const Type val)
9112450Sgabeblack@google.com    {
9212450Sgabeblack@google.com        Base::setter(__storage, val);
9312450Sgabeblack@google.com        return val;
9412450Sgabeblack@google.com    }
9512450Sgabeblack@google.com
9612450Sgabeblack@google.com    Type
9712450Sgabeblack@google.com    operator=(BitfieldTypeImpl<Base> const & other)
9812450Sgabeblack@google.com    {
9912450Sgabeblack@google.com        return *this = (Type)other;
10012450Sgabeblack@google.com    }
10112450Sgabeblack@google.com};
10212450Sgabeblack@google.com
10312450Sgabeblack@google.com//A wrapper for the above class which allows setting and getting.
10412450Sgabeblack@google.comtemplate<class Base>
10512450Sgabeblack@google.comclass BitfieldType : public BitfieldTypeImpl<Base>
10612450Sgabeblack@google.com{
10712450Sgabeblack@google.com  protected:
10812450Sgabeblack@google.com    using Impl = BitfieldTypeImpl<Base>;
10912450Sgabeblack@google.com    using typename Impl::Type;
11012450Sgabeblack@google.com
11112450Sgabeblack@google.com  public:
11212450Sgabeblack@google.com    operator Type () const { return Impl::operator Type(); }
11312450Sgabeblack@google.com    Type operator=(const Type val) { return Impl::operator=(val); }
11412450Sgabeblack@google.com    Type
11512450Sgabeblack@google.com    operator=(BitfieldType<Base> const & other)
11612450Sgabeblack@google.com    {
11712450Sgabeblack@google.com        return Impl::operator=(other);
11812450Sgabeblack@google.com    }
11912450Sgabeblack@google.com};
12012450Sgabeblack@google.com
12112450Sgabeblack@google.com//A wrapper which only supports getting.
12212450Sgabeblack@google.comtemplate<class Base>
12312450Sgabeblack@google.comclass BitfieldROType : public BitfieldTypeImpl<Base>
12412450Sgabeblack@google.com{
12512450Sgabeblack@google.com  public:
12612450Sgabeblack@google.com    using Impl = BitfieldTypeImpl<Base>;
12712450Sgabeblack@google.com    using typename Impl::Type;
12812450Sgabeblack@google.com
12912450Sgabeblack@google.com    Type operator=(BitfieldROType<Base> const &other) = delete;
13012450Sgabeblack@google.com    operator Type () const { return Impl::operator Type(); }
13112450Sgabeblack@google.com};
13212450Sgabeblack@google.com
13312450Sgabeblack@google.com//A wrapper which only supports setting.
13412450Sgabeblack@google.comtemplate <class Base>
13512450Sgabeblack@google.comclass BitfieldWOType : public BitfieldTypeImpl<Base>
13612450Sgabeblack@google.com{
13712450Sgabeblack@google.com  protected:
13812450Sgabeblack@google.com    using Impl = BitfieldTypeImpl<Base>;
13912450Sgabeblack@google.com    using typename Impl::Type;
14012450Sgabeblack@google.com
14112450Sgabeblack@google.com  public:
14212450Sgabeblack@google.com    Type operator=(const Type val) { return Impl::operator=(val); }
14312450Sgabeblack@google.com    Type
14412450Sgabeblack@google.com    operator=(BitfieldWOType<Base> const & other)
14512450Sgabeblack@google.com    {
14612450Sgabeblack@google.com        return Impl::operator=(other);
14712450Sgabeblack@google.com    }
14812450Sgabeblack@google.com};
14912450Sgabeblack@google.com
1504680Sgblack@eecs.umich.edu//This namespace is for classes which implement the backend of the BitUnion
15112450Sgabeblack@google.com//stuff. Don't use any of these directly.
1524680Sgblack@eecs.umich.edunamespace BitfieldBackend
1534680Sgblack@eecs.umich.edu{
15412450Sgabeblack@google.com    template<class Storage, int first, int last>
15512450Sgabeblack@google.com    class Unsigned
1564680Sgblack@eecs.umich.edu    {
15712450Sgabeblack@google.com        static_assert(first >= last,
15812450Sgabeblack@google.com                      "Bitfield ranges must be specified as <msb, lsb>");
15912450Sgabeblack@google.com
1604680Sgblack@eecs.umich.edu      protected:
16112450Sgabeblack@google.com        uint64_t
16212450Sgabeblack@google.com        getter(const Storage &storage) const
1634680Sgblack@eecs.umich.edu        {
16412450Sgabeblack@google.com            return bits(storage, first, last);
1654680Sgblack@eecs.umich.edu        }
1664680Sgblack@eecs.umich.edu
16712450Sgabeblack@google.com        void
16812450Sgabeblack@google.com        setter(Storage &storage, uint64_t val)
1694680Sgblack@eecs.umich.edu        {
17012450Sgabeblack@google.com            replaceBits(storage, first, last, val);
1714680Sgblack@eecs.umich.edu        }
1724680Sgblack@eecs.umich.edu    };
1734680Sgblack@eecs.umich.edu
17412450Sgabeblack@google.com    template<class Storage, int first, int last>
17512450Sgabeblack@google.com    class Signed
17612450Sgabeblack@google.com    {
17712450Sgabeblack@google.com        static_assert(first >= last,
17812450Sgabeblack@google.com                      "Bitfield ranges must be specified as <msb, lsb>");
17912450Sgabeblack@google.com
18012450Sgabeblack@google.com      protected:
18112450Sgabeblack@google.com        int64_t
18212450Sgabeblack@google.com        getter(const Storage &storage) const
18312450Sgabeblack@google.com        {
18412450Sgabeblack@google.com            return sext<first - last + 1>(bits(storage, first, last));
18512450Sgabeblack@google.com        }
18612450Sgabeblack@google.com
18712450Sgabeblack@google.com        void
18812450Sgabeblack@google.com        setter(Storage &storage, int64_t val)
18912450Sgabeblack@google.com        {
19012450Sgabeblack@google.com            replaceBits(storage, first, last, val);
19112450Sgabeblack@google.com        }
19212450Sgabeblack@google.com    };
19312450Sgabeblack@google.com
19412450Sgabeblack@google.com    //This class contains the basic bitfield types which are automatically
19512450Sgabeblack@google.com    //available within a BitUnion. They inherit their Storage type from the
19612450Sgabeblack@google.com    //containing BitUnion.
19712450Sgabeblack@google.com    template<class Storage>
19812450Sgabeblack@google.com    class BitfieldTypes
1994680Sgblack@eecs.umich.edu    {
2004680Sgblack@eecs.umich.edu      protected:
20112450Sgabeblack@google.com
2024680Sgblack@eecs.umich.edu        template<int first, int last=first>
20312450Sgabeblack@google.com        using Bitfield = BitfieldType<Unsigned<Storage, first, last> >;
20412450Sgabeblack@google.com        template<int first, int last=first>
20512450Sgabeblack@google.com        using BitfieldRO =
20612450Sgabeblack@google.com                BitfieldROType<Unsigned<Storage, first, last> >;
20712450Sgabeblack@google.com        template<int first, int last=first>
20812450Sgabeblack@google.com        using BitfieldWO =
20912450Sgabeblack@google.com                BitfieldWOType<Unsigned<Storage, first, last> >;
21010289SAndreas.Sandberg@ARM.com
2114680Sgblack@eecs.umich.edu        template<int first, int last=first>
21212450Sgabeblack@google.com        using SignedBitfield =
21312450Sgabeblack@google.com                BitfieldType<Signed<Storage, first, last> >;
2144680Sgblack@eecs.umich.edu        template<int first, int last=first>
21512450Sgabeblack@google.com        using SignedBitfieldRO =
21612450Sgabeblack@google.com                BitfieldROType<Signed<Storage, first, last> >;
21712450Sgabeblack@google.com        template<int first, int last=first>
21812450Sgabeblack@google.com        using SignedBitfieldWO =
21912450Sgabeblack@google.com                BitfieldWOType<Signed<Storage, first, last> >;
2204680Sgblack@eecs.umich.edu    };
2214680Sgblack@eecs.umich.edu
2224680Sgblack@eecs.umich.edu    //When a BitUnion is set up, an underlying class is created which holds
2234680Sgblack@eecs.umich.edu    //the actual union. This class then inherits from it, and provids the
2244680Sgblack@eecs.umich.edu    //implementations for various operators. Setting things up this way
2254680Sgblack@eecs.umich.edu    //prevents having to redefine these functions in every different BitUnion
2264680Sgblack@eecs.umich.edu    //type. More operators could be implemented in the future, as the need
2274680Sgblack@eecs.umich.edu    //arises.
22812450Sgabeblack@google.com    template <class Base>
2294680Sgblack@eecs.umich.edu    class BitUnionOperators : public Base
2304680Sgblack@eecs.umich.edu    {
23112450Sgabeblack@google.com        static_assert(sizeof(Base) == sizeof(typename Base::__StorageType),
23212450Sgabeblack@google.com                      "BitUnion larger than its storage type.");
23312450Sgabeblack@google.com
2344680Sgblack@eecs.umich.edu      public:
23512450Sgabeblack@google.com        BitUnionOperators(typename Base::__StorageType const &val)
2364681Sgblack@eecs.umich.edu        {
23712450Sgabeblack@google.com            Base::__storage = val;
2384681Sgblack@eecs.umich.edu        }
2394681Sgblack@eecs.umich.edu
2404681Sgblack@eecs.umich.edu        BitUnionOperators() {}
2414681Sgblack@eecs.umich.edu
24212450Sgabeblack@google.com        operator const typename Base::__StorageType () const
2434680Sgblack@eecs.umich.edu        {
24412450Sgabeblack@google.com            return Base::__storage;
2454680Sgblack@eecs.umich.edu        }
2464680Sgblack@eecs.umich.edu
24712450Sgabeblack@google.com        typename Base::__StorageType
24812450Sgabeblack@google.com        operator=(typename Base::__StorageType const &val)
2494680Sgblack@eecs.umich.edu        {
25012450Sgabeblack@google.com            Base::__storage = val;
25112450Sgabeblack@google.com            return val;
2524680Sgblack@eecs.umich.edu        }
2534680Sgblack@eecs.umich.edu
25412450Sgabeblack@google.com        typename Base::__StorageType
25512450Sgabeblack@google.com        operator=(BitUnionOperators const &other)
25610640Sgabeblack@google.com        {
25712450Sgabeblack@google.com            Base::__storage = other;
25812450Sgabeblack@google.com            return Base::__storage;
25910640Sgabeblack@google.com        }
26010640Sgabeblack@google.com
2614680Sgblack@eecs.umich.edu        bool
26212450Sgabeblack@google.com        operator<(Base const &base) const
2634680Sgblack@eecs.umich.edu        {
26412450Sgabeblack@google.com            return Base::__storage < base.__storage;
2654680Sgblack@eecs.umich.edu        }
2664680Sgblack@eecs.umich.edu
2674680Sgblack@eecs.umich.edu        bool
26812450Sgabeblack@google.com        operator==(Base const &base) const
2694680Sgblack@eecs.umich.edu        {
27012450Sgabeblack@google.com            return Base::__storage == base.__storage;
2714680Sgblack@eecs.umich.edu        }
2724680Sgblack@eecs.umich.edu    };
2734680Sgblack@eecs.umich.edu}
2744680Sgblack@eecs.umich.edu
2754680Sgblack@eecs.umich.edu//This macro is a backend for other macros that specialize it slightly.
2764680Sgblack@eecs.umich.edu//First, it creates/extends a namespace "BitfieldUnderlyingClasses" and
2774680Sgblack@eecs.umich.edu//sticks the class which has the actual union in it, which
2784680Sgblack@eecs.umich.edu//BitfieldOperators above inherits from. Putting these classes in a special
2794680Sgblack@eecs.umich.edu//namespace ensures that there will be no collisions with other names as long
2804680Sgblack@eecs.umich.edu//as the BitUnion names themselves are all distinct and nothing else uses
2814680Sgblack@eecs.umich.edu//the BitfieldUnderlyingClasses namespace, which is unlikely. The class itself
28212450Sgabeblack@google.com//creates a typedef of the "type" parameter called __StorageType. This allows
2834680Sgblack@eecs.umich.edu//the type to propagate outside of the macro itself in a controlled way.
2844680Sgblack@eecs.umich.edu//Finally, the base storage is defined which BitfieldOperators will refer to
2854680Sgblack@eecs.umich.edu//in the operators it defines. This macro is intended to be followed by
2864680Sgblack@eecs.umich.edu//bitfield definitions which will end up inside it's union. As explained
28712450Sgabeblack@google.com//above, these is overlayed the __storage member in its entirety by each of the
2884680Sgblack@eecs.umich.edu//bitfields which are defined in the union, creating shared storage with no
2894680Sgblack@eecs.umich.edu//overhead.
2904680Sgblack@eecs.umich.edu#define __BitUnion(type, name) \
2915442Sgblack@eecs.umich.edu    class BitfieldUnderlyingClasses##name : \
2924680Sgblack@eecs.umich.edu        public BitfieldBackend::BitfieldTypes<type> \
2934680Sgblack@eecs.umich.edu    { \
2944680Sgblack@eecs.umich.edu      public: \
29512450Sgabeblack@google.com        typedef type __StorageType; \
2964680Sgblack@eecs.umich.edu        union { \
29712450Sgabeblack@google.com            type __storage;
2984680Sgblack@eecs.umich.edu
2994680Sgblack@eecs.umich.edu//This closes off the class and union started by the above macro. It is
3004680Sgblack@eecs.umich.edu//followed by a typedef which makes "name" refer to a BitfieldOperator
3014680Sgblack@eecs.umich.edu//class inheriting from the class and union just defined, which completes
3024680Sgblack@eecs.umich.edu//building up the type for the user.
3034680Sgblack@eecs.umich.edu#define EndBitUnion(name) \
3044680Sgblack@eecs.umich.edu        }; \
3054680Sgblack@eecs.umich.edu    }; \
3064680Sgblack@eecs.umich.edu    typedef BitfieldBackend::BitUnionOperators< \
3075442Sgblack@eecs.umich.edu        BitfieldUnderlyingClasses##name> name;
3084680Sgblack@eecs.umich.edu
3094680Sgblack@eecs.umich.edu//This sets up a bitfield which has other bitfields nested inside of it. The
31012450Sgabeblack@google.com//__storage member functions like the "underlying storage" of the top level
3114680Sgblack@eecs.umich.edu//BitUnion. Like everything else, it overlays with the top level storage, so
3124680Sgblack@eecs.umich.edu//making it a regular bitfield type makes the entire thing function as a
3134680Sgblack@eecs.umich.edu//regular bitfield when referred to by itself.
31412450Sgabeblack@google.com#define __SubBitUnion(name, fieldType, ...) \
31512450Sgabeblack@google.com    class \
3164680Sgblack@eecs.umich.edu    { \
3174680Sgblack@eecs.umich.edu      public: \
3184680Sgblack@eecs.umich.edu        union { \
31912450Sgabeblack@google.com            fieldType<__VA_ARGS__> __storage;
3204680Sgblack@eecs.umich.edu
3214680Sgblack@eecs.umich.edu//This closes off the union created above and gives it a name. Unlike the top
3224680Sgblack@eecs.umich.edu//level BitUnion, we're interested in creating an object instead of a type.
3234680Sgblack@eecs.umich.edu//The operators are defined in the macro itself instead of a class for
3244680Sgblack@eecs.umich.edu//technical reasons. If someone determines a way to move them to one, please
3254680Sgblack@eecs.umich.edu//do so.
3264680Sgblack@eecs.umich.edu#define EndSubBitUnion(name) \
3274680Sgblack@eecs.umich.edu        }; \
32812450Sgabeblack@google.com        inline operator __StorageType () const \
32912450Sgabeblack@google.com        { return __storage; } \
3304680Sgblack@eecs.umich.edu        \
33112450Sgabeblack@google.com        inline __StorageType operator = (const __StorageType & _storage) \
33212450Sgabeblack@google.com        { return __storage = _storage;} \
3334680Sgblack@eecs.umich.edu    } name;
3344680Sgblack@eecs.umich.edu
3354680Sgblack@eecs.umich.edu//Regular bitfields
3364680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
3374680Sgblack@eecs.umich.edu#define SubBitUnion(name, first, last) \
33812450Sgabeblack@google.com    __SubBitUnion(name, Bitfield, first, last)
3394680Sgblack@eecs.umich.edu
3404680Sgblack@eecs.umich.edu//Regular bitfields
3414680Sgblack@eecs.umich.edu//These define macros for read/write regular bitfield based subbitfields.
3424680Sgblack@eecs.umich.edu#define SignedSubBitUnion(name, first, last) \
34312450Sgabeblack@google.com    __SubBitUnion(name, SignedBitfield, first, last)
3444680Sgblack@eecs.umich.edu
3454680Sgblack@eecs.umich.edu//Use this to define an arbitrary type overlayed with bitfields.
3464680Sgblack@eecs.umich.edu#define BitUnion(type, name) __BitUnion(type, name)
3474680Sgblack@eecs.umich.edu
3484680Sgblack@eecs.umich.edu//Use this to define conveniently sized values overlayed with bitfields.
3494680Sgblack@eecs.umich.edu#define BitUnion64(name) __BitUnion(uint64_t, name)
3504680Sgblack@eecs.umich.edu#define BitUnion32(name) __BitUnion(uint32_t, name)
3514680Sgblack@eecs.umich.edu#define BitUnion16(name) __BitUnion(uint16_t, name)
3524680Sgblack@eecs.umich.edu#define BitUnion8(name) __BitUnion(uint8_t, name)
3534680Sgblack@eecs.umich.edu
35412451Sgabeblack@google.com
35512451Sgabeblack@google.com//These templates make it possible to define other templates related to
35612451Sgabeblack@google.com//BitUnions without having to refer to internal typedefs or the BitfieldBackend
35712451Sgabeblack@google.com//namespace.
35812451Sgabeblack@google.com
35912451Sgabeblack@google.com//To build a template specialization which works for all BitUnions, accept a
36012451Sgabeblack@google.com//template argument T, and then use BitUnionType<T> as an argument in the
36112451Sgabeblack@google.com//template. To refer to the basic type the BitUnion wraps, use
36212451Sgabeblack@google.com//BitUnionBaseType<T>.
36312451Sgabeblack@google.com
36412451Sgabeblack@google.com//For example:
36512451Sgabeblack@google.com//template <typename T>
36612451Sgabeblack@google.com//void func(BitUnionType<T> u) { BitUnionBaseType<T> b = u; }
36712451Sgabeblack@google.com
36812451Sgabeblack@google.com//Also, BitUnionBaseType can be used on a BitUnion type directly.
36912451Sgabeblack@google.com
37012451Sgabeblack@google.comtemplate <typename T>
37112451Sgabeblack@google.comusing BitUnionType = BitfieldBackend::BitUnionOperators<T>;
37212451Sgabeblack@google.com
37312451Sgabeblack@google.comnamespace BitfieldBackend
37412451Sgabeblack@google.com{
37512451Sgabeblack@google.com    template<typename T>
37612451Sgabeblack@google.com    struct BitUnionBaseType
37712451Sgabeblack@google.com    {
37812451Sgabeblack@google.com        typedef typename BitUnionType<T>::__StorageType Type;
37912451Sgabeblack@google.com    };
38012451Sgabeblack@google.com
38112451Sgabeblack@google.com    template<typename T>
38212451Sgabeblack@google.com    struct BitUnionBaseType<BitUnionType<T> >
38312451Sgabeblack@google.com    {
38412451Sgabeblack@google.com        typedef typename BitUnionType<T>::__StorageType Type;
38512451Sgabeblack@google.com    };
38612451Sgabeblack@google.com}
38712451Sgabeblack@google.com
38812451Sgabeblack@google.comtemplate <typename T>
38912451Sgabeblack@google.comusing BitUnionBaseType = typename BitfieldBackend::BitUnionBaseType<T>::Type;
39012451Sgabeblack@google.com
39112453Sgabeblack@google.comnamespace std
39212453Sgabeblack@google.com{
39312453Sgabeblack@google.com    template <typename T>
39412453Sgabeblack@google.com    struct hash;
39512453Sgabeblack@google.com
39612453Sgabeblack@google.com    template <typename T>
39712453Sgabeblack@google.com    struct hash<BitUnionType<T> > : public hash<BitUnionBaseType<T> >
39812453Sgabeblack@google.com    {
39912453Sgabeblack@google.com        size_t
40012453Sgabeblack@google.com        operator() (const BitUnionType<T> &val) const
40112453Sgabeblack@google.com        {
40212453Sgabeblack@google.com            return hash<BitUnionBaseType<T> >::operator()(val);
40312453Sgabeblack@google.com        }
40412453Sgabeblack@google.com    };
40512453Sgabeblack@google.com}
40612453Sgabeblack@google.com
4074680Sgblack@eecs.umich.edu#endif // __BASE_BITUNION_HH__
408