Looking to arrayize something

This is a discussion on Looking to arrayize something within the C++ Programming forums, part of the General Programming Boards category; OK, so I am clueless to a good title for the subject. Anyway, what I have is: Code: #ifndef TOGGLES_HPP_20120215_1624 ...

  1. #1
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,424

    Looking to arrayize something

    OK, so I am clueless to a good title for the subject.
    Anyway, what I have is:

    Code:
    #ifndef TOGGLES_HPP_20120215_1624
    #define TOGGLES_HPP_20120215_1624
    
    #ifndef BITFIELD_DYN_HPP_20120215_1257
    #define BITFIELD_DYN_HPP_20120215_1257
    
    namespace bitfield
    {
    	template<typename adr_t> class get_op { public: static bool get(volatile adr_t* adr, int bit) { return *adr & (1 << (bit - 1)); } };
    	template<typename adr_t> class set_op { public: static bool set(volatile adr_t* adr, int bit) { *adr |= (1 << (bit - 1)); } };
    	template<typename adr_t> class clear_op { public: static bool get(volatile adr_t* adr, int bit) { *adr &= ~(1 << (bit - 1)); } };
    	
    	template<typename adr_t>
    	class trio: public get_op<adr_t>, public set_op<adr_t>, public clear_op<adr_t> {};
    	
    	template<int adr, int bit, typename adr_t>
    	class clear_get: public get_op<adr, bit, adr_t>, public clear_op<adr, bit, adr_t> {};
    
    	template<int adr, int bit, typename adr_t>
    	class clear_set: public set_op<adr, bit, adr_t>, public clear_op<adr, bit, adr_t> {};
    }
    
    namespace bitfield
    {
    	template<typename adr_t> bool get(volatile adr_t* adr, int bit) { return *adr & (1 << (bit - 1)); }
    	template<typename adr_t> void set(volatile adr_t* adr, int bit) { *adr |= (1 << (bit - 1)); }
    	template<typename adr_t> void clear(volatile adr_t* adr, int bit) { *adr &= ~(1 << (bit - 1)); }
    }
    
    #endif /*BITFIELD_HPP_*/
    
    #include <assert.h>
    
    namespace io_toggles
    {
    	namespace detail
    	{
    		const int data = 0x840;
    		const int interrupt = 0x848;
    		const int interrupt_restore = 0x84C;
    
    		template<int bit>
    		class abstract_toggle: public base_toggle
    		{
    		public:
    			class : public bitfield::get_op<detail::data, bit, char> {} status;
    			class 
    			{
    			public:
    				class : public bitfield::trio<detail::interrupt, bit, char> {} status;
    				class : public bitfield::get_op<detail::interrupt_restore, bit, char> {} restore;
    			};
    		};
    	}
    
    	typedef const detail::abstract_toggle<1> key1;
    	typedef const detail::abstract_toggle<2> key2;
    	typedef const detail::abstract_toggle<3> key3;
    	typedef const detail::abstract_toggle<4> key4;
    	typedef const detail::abstract_toggle<5> key5;
    	typedef const detail::abstract_toggle<6> key6;
    	typedef const detail::abstract_toggle<7> key7;
    	typedef const detail::abstract_toggle<8> key8;
    	typedef const detail::abstract_toggle<9> key9;
    	typedef const detail::abstract_toggle<10> key10;
    	typedef const detail::abstract_toggle<11> key11;
    	typedef const detail::abstract_toggle<12> key12;
    	typedef const detail::abstract_toggle<13> key13;
    	typedef const detail::abstract_toggle<14> key14;
    	typedef const detail::abstract_toggle<15> key15;
    	typedef const detail::abstract_toggle<16> key16;
    	typedef const detail::abstract_toggle<17> key17;
    	typedef const detail::abstract_toggle<18> key18;
    }
    
    #endif /*TOGGLES_HPP_*/
    The goal of what I want is to be able to do

    Code:
    int main()
    {
        for (int i = 0; i < 18; i++)
            io_toggles::key[i].interrupt().status().set();
    }
    In some way or form. The syntax doesn't matter--what matters is that I am able to do that. It's horrible to just have to put 18 long identical lines of code.
    ...But I can't find any good solution that doesn't require a lot of code and duplication.

    Anyone else have any ideas to share?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #2
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    681
    I would be glad if you explained what is so different in this bit-field implementation. I am also wondering why you don't use unsigned integers for bit manipulations.

    All I can say for now is that I would certainly drop this template madness.
    I never put signature, but I decided to make an exception.

  3. #3
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,424
    But I love template madness :P
    Anyway, I'm surprised you haven't figured out what this is judging from the code with the interrupt names and hard-coded memory addresses. It's not a bitfield implementation. It's an implementation to hide the ugliness of hardware! Instead of having to write and read bits and bytes from arbitrary memory addresses, I'd rather try to hide it underneath a beautiful abstraction mechanism.
    So anyway, this is just my first attempt on it. I've tried other approaches, too. It's just that I couldn't get anything satisfactory.
    It doesn't have to be templates all the way. I've tried without, but it just becomes so much messy code.
    I am thinking right now that the best approach that I've found so far is basically to go dynamic (ie, remove bits and address from templates) and use some macro obfuscation.

    Oh, and as for the signed shifting, it's because I loathe unsigned integers. Basically, it is bothersome to check if you get overflow with unsigned integers and no compiler I know of complains when you send a signed integer into a function expecting an unsigned one (the compiler didn't even complain when passing -1 to a function expecting an unsigned integer!).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    681
    Anyway, I'm surprised you haven't figured out what this is judging from the code with the interrupt names and hard-coded memory addresses. It's not a bitfield implementation. It's an implementation to hide the ugliness of hardware! Instead of having to write and read bits and bytes from arbitrary memory addresses, I'd rather try to hide it underneath a beautiful abstraction mechanism.
    So anyway, this is just my first attempt on it. I've tried other approaches, too. It's just that I couldn't get anything satisfactory.
    It doesn't have to be templates all the way. I've tried without, but it just becomes so much messy code.
    I am thinking right now that the best approach that I've found so far is basically to go dynamic (ie, remove bits and address from templates) and use some macro obfuscation.
    The template madness misleaded me ;]! At first I was thinking about networking code or something, but anyway the lack of runtime things would explain this.

    Actually, I have been in a very similar situation recently when working with Direct3D 9. I was trying to hide its ugliness by creating wrappers and utilitiy functions. The problem was that the API (actually only a useful part of it) was too large to wrap. I wasted a lot of time on thinking about different approaches - from templates to runtime, ending on RTTI. All of them failed, simply because there was no clean way to make the classes renderer-independent. I had to turn off object-oriented thinking and started creating one nasty big class containing device and useful rendering functions. Finally I decided to switch to Direct3D 11 which is free from all the FFP mess.
    What I want to say is that a couple of naive low level functions (or macros as you suggested) might be a better solution, considering time you have already wasted on these templates. Maybe instead of abstracting the hardware, just create an isolated platform-specific code (pure C ?), and put the abstraction layer higher?
    I never put signature, but I decided to make an exception.

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,167
    Code:
        for (int i = 0; i < 18; i++)
            io_toggles::key[i].interrupt().status().set();
    This has the same answer I give every time someone tries to make template methods behave polymorphic with respect to iterating over class instances.

    1): Change the way the classes work so that a virtual function can be used as an interface and iterate over instances normally.
    2): Change the way you are iterating over the instances to use only operations that can be performed at compile-time.

    In this case the first one is pretty easy as you are only using templates as an implementation technique so wrapping them in an interface should take minutes. A higher abstraction (template factory producing instances of template classes) allows code very similar to what you've written to work.

    The second one is only ever useful (actually, only ever possible) if the size of the operations is known at compile time. If you are primarily iterating over a fixed set of types (always all keys or only keys 1-12 for example) you can setup a simple meta-programming facility to "loop" over the kays and pass them off to a given template function (an actual run-time function) with a few tens of minutes of work... assuming you really do love the template madness.

    Soma

  6. #6
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,627
    Quote Originally Posted by Elysia View Post
    Oh, and as for the signed shifting, it's because I loathe unsigned integers. Basically, it is bothersome to check if you get overflow with unsigned integers and no compiler I know of complains when you send a signed integer into a function expecting an unsigned one (the compiler didn't even complain when passing -1 to a function expecting an unsigned integer!).
    You're worried about checking for overflow in bit fiddling, yet you use signed shifting. Have you ever consulted the standard on this? The C++0x working draft has this to say.

    2 The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned
    type, the value of the result is E1 2^(E2), reduced modulo one more than the maximum value representable
    in the result type. Otherwise, if E1 has a signed type and non-negative value, and E12^(E2) is representable
    in the result type, then that is the resulting value; otherwise, the behavior is undefined.
    3 The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed
    type and a non-negative value, the value of the result is the integral part of the quotient of E1/2^(E2). If E1
    has a signed type and a negative value, the resulting value is implementation-defined.
    If I were as worried as you are about this I would use unsigned shifting since you will always know what the values are.
    Last edited by whiteflags; 02-15-2012 at 07:24 PM. Reason: fixed my quote

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    You might want to look at Boost.Fusion.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,424
    That sounds very interesting, but I don't know how well that would work since this is a special compiler, and I have no idea if it can muster boost or how to configure it to include boost.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,424
    Ah, I had my doubts when you mentioned Boost, CornedBee.
    But after some researching, it compiles just fine! Using this and compile-time iteration, I can exactly what I want, so thanks!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,424
    This is what I ended up with, for others interested;

    Code:
    #ifndef BITFIELD_HPP_20120215_1257
    #define BITFIELD_HPP_20120215_1257
    
    namespace bitfield
    {
    	template<int adr, int bit, typename adr_t> class get_op { public: static bool get() { return *(volatile adr_t*)adr & (1 << (bit - 1)); } };
    	template<int adr, int bit, typename adr_t> class set_op { public: static void set() { *(volatile adr_t*)adr |= (1 << (bit - 1)); } };
    	template<int adr, int bit, typename adr_t> class clear_op { public: static void clear() { *(volatile adr_t*)adr &= ~(1 << (bit - 1)); } };
    	
    	template<int adr, int bit, typename adr_t>
    	class trio: public get_op<adr, bit, adr_t>, public set_op<adr, bit, adr_t>, public clear_op<adr, bit, adr_t> {};
    	
    	template<int adr, int bit, typename adr_t>
    	class clear_get: public get_op<adr, bit, adr_t>, public clear_op<adr, bit, adr_t> {};
    
    	template<int adr, int bit, typename adr_t>
    	class clear_set: public set_op<adr, bit, adr_t>, public clear_op<adr, bit, adr_t> {};
    }
    
    #endif /*BITFIELD_HPP_*/
    
    
    #define FUSION_MAX_VECTOR_SIZE 18
    #include <boost/fusion/algorithm.hpp>
    #include <boost/fusion/sequence.hpp>
    #include <boost/fusion/include/sequence.hpp>
    #include <boost/fusion/container/vector.hpp>
    #undef FUSION_MAX_VECTOR_SIZE
    
    namespace io_toggles
    {
    	namespace detail
    	{
    		const int data = 0x850;
    		const int interrupt = 0x858;
    		const int interrupt_restore = 0x85C;
    	}
    
    	template<int bit>
    	class toggle
    	{
    	public:
    		class : public bitfield::get_op<detail::data, bit, int> {} status;
    		class 
    		{
    		public:
    			class : public bitfield::trio<detail::interrupt, bit, int> {} status;
    			class : public bitfield::get_op<detail::interrupt_restore, bit, int> {} restore;
    		} interrupt;
    	};
    	
    	#define TGL(n) toggle<n>
    	typedef boost::fusion::vector<TGL(1), TGL(2), TGL(3), TGL(4), TGL(5), TGL(6), TGL(7), TGL(8), TGL(9),
    		TGL(10), TGL(11), TGL(12), TGL(13), TGL(14), TGL(15), TGL(16), TGL(17), TGL(18)> key_t;
    	#undef TGL
    
    	key_t key;
    }
    
    struct tmp
    {
    	template<int N>
    	void operator ()(io_toggles::toggle<N>& elem) const
    	{
    		elem.interrupt.status.set();
    	}
    };
    
    extern "C"
    {
    
    void init_toggles()
    {
     	boost::fusion::for_each(io_toggles::key, tmp());
    }
    	
    }
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21