John,
On 10/11/10 13:00, john.aynsley@doulos.com wrote:
> I am fine with a verbose name in this case, because it is doing something 
> non-obvious so we would want it to stand out.
Ok.
> I agree with sc_vector_assembly<T,MT>. Does this need to be in the LRM? 
> Which bits of it are visible in application code? Can you give some 
> examples?
Essentially, it's the return-type of sc_assemble_vector.  The reason for
the existence of the helper function sc_assemble_vector is to detect the
"correct" type of the referenced member from the given pointer-to-member
argument to the function.
Example:
 struct Initiator1: sc_module
 {
    // ...
    sc_port<i_f> port;
 };
sc_vector_assembly< Initiator1, sc_port<i_f> > ports_assembly  = 	
   sc_assemble_vector( my_init_vec, &Initiator1::port );
With the function, you don't need to specify 'sc_port<i_f>' directly in
the bind expressions.
The above code is currently valid in the PoC implementation.  The
assembly is Copyable, since it needs to be passed by-value to the bind()
function overload.
But in the current implementation, the constructor
  sc_vector_assembly( sc_vector<T> &, MT (T::*MemPtr) )
is private and may only be invoked by the implementation of
sc_assemble_vector.
  The proxy class implements the mostly interface as if it would be a
first-class sc_vector< MT >.  An exception are the for the sc_object
functions, since the assembly itself is not derived from sc_object for
now (it's a temporary helper anyhow).
The other functions
  begin(), end(), et.al.
  size(), get_elements()
  operator[], at()
  bind() template functions
are meant to be accessible by the application.
So you can do things like:
   sc_assemble_vector( my_init_vec, &Initiator1::port )
        .size();    // == my_init_vec.size()
        .begin();   // == iterator pointing to my_init_vec.begin()->port
        [0].name(); // == my_init_vec[0].port.name()
You can find an attempt for a corresponding wording in the latest
version of the sc_vector proposal.
Greetings from Oldenburg,
  Philipp
> From:
> "Philipp A. Hartmann" <philipp.hartmann@offis.de>
> To:
> john.aynsley@doulos.com
> Cc:
> systemc-p1666-technical@eda.org
> Date:
> 10/11/2010 11:35
> Subject:
> Re: sc_vector proposal
> 
> 
> 
> John,
> 
> I'm fine with sc_assemble_vector, although it's quite verbose.  But I
> see your point in having a name related to sc_vector.
> 
>   Shall we change the name of the implementation-defined helper class
> sc_vector_view<T,MT> as well?  sc_vector_assembly<T,MT> perhaps?
> 
> Thanks,
> Philipp
> 
> On 10/11/10 12:28, john.aynsley@doulos.com wrote:
>> Philipp, All,
>>
>> Regarding the binding iterators: Having vector binding capability is 
>> really cool, and you do indeed want a way to bind part-vectors. Given 
> that 
>> there is some precedent in STL, the approach you have chosen is fine, 
> i.e. 
>> returning the position of the next unbound element.
>>
>> Regarding the name sc_view: It is just a name, but I think we could do 
>> better. I got the database reference, but I want a name that tells me 
> that 
>> I'm doing something related to vectors. I propose
>>
>>         sc_assemble_vector(initiator_vec, &Initiator1::port).bind( 
>> sc_assemble_vector(target_vec, &Target::xp) );
>>
>> What do people think?
>>
>>
>> Regarding the creator: Okay, I buy that, unless anyone else has any 
> smart 
>> ideas?
>>
>> John A
>>
>>
>>
>>
>> From:
>> "Philipp A. Hartmann" <philipp.hartmann@offis.de>
>> To:
>> john.aynsley@doulos.com
>> Cc:
>> systemc-p1666-technical@eda.org
>> Date:
>> 09/11/2010 18:36
>> Subject:
>> Re: sc_vector proposal
>>
>>
>>
>> John,
>>
>> thanks for your comments and your nice review of the proposal.
>> Please find my answers to your questions embedded below.
>>
>> On 09/11/10 14:06, john.aynsley@doulos.com wrote:
>>
>> [snip basic feature description]
>>
>>> Then we add a few wrinkles. It is possible to bind a vector-of-ports to 
> 
>> a 
>>> vector-of-channels directly, with no explicit loop, e.g.
>>>
>>>         module_inst->ports.bind( sigs );  // ports is a vector-of-ports 
> 
>>> and sigs is a vector-of-sigs
>>>
>>> Very nice. It is also possible to bind just a subset of the 
>>> vector-of-ports, then come back for another pass later:
>>>
>>>         typedef sc_vector<sc_inout<int> > port_type;
>>>         port_type::iterator it;
>>>
>>>         // Bind upper half of ports vector to hi_sigs 
>>>         it = module_inst->ports.bind( hi_sigs.begin(), hi_sigs.end() ); 
> 
>> // 
>>> hi_sigs.size() < ports.size()
>>>
>>>         // Bind lower half of ports vector to lo_sigs 
>>>         it = module_inst->ports.bind( lo_sigs.begin(), lo_sigs.end(), 
>> it); 
>>>   // Notice binding starts from position 'it' within ports vector
>>>
>>> The above syntax - having bind return the position of the 1st unbound 
>>> element - seems a little arcane to me. Are we all okay with it?
>>
>> Returning the "last" iterator follows the approach known from some of
>> the iterator-based STL algorithms, like std::copy or std::transform.
>> To me, this is the simplest way to define the interface.  But I'm free
>> to any suggestions in that area.
>>
>> Note, that the user can of course ignore the return value of the bind
>> function and use an explicit iterator for the second bind offset:
>>
>>   module_inst->ports.bind( lo_sigs.begin(), lo_sigs.end()
>>                          , module_inst.begin() + hi_sigs.size() );
>>
>> If we feel, that this iterator-based interface is too complex to
>> understand or describe, we can also drop it from the standard.  Manually
>> looping over parts of the vectors is still possible and maybe easier to
>> explain:
>>
>>   port_type it = module_inst.ports.begin();
>>
>>   for( int i=0; i<hi_sigs.size(); ++i, ++it );
>>     it->bind( hi_sigs[i] );
>>
>>   for( int i=0; i<lo_sigs.size(); ++i, ++it );
>>     it->bind( lo_sigs[i] );
>>
>> The returned iterator from the bind() calls can also be used to check,
>> if all elements have been bound:
>>
>>   sc_assert( it == module_inst->ports.end() ); // all bound
>>
>>> But sometimes, rather than having a vector-of-ports, you might have a 
>>> vector-of-modules each containing a single port. In this case it is 
>>> possible to treat these ports distributed across multiple modules as 
> one 
>>
>>> vector, using sc_view. For example:
>>>
>>>         struct Initiator1: sc_module
>>>         {
>>>                 sc_port<i_f> port;
>>>                 ...
>>>         struct Target: public sc_module, private i_f
>>>         {
>>>                 sc_export<i_f> xp;
>>>                 ...
>>>
>>>         sc_vector<Initiator1> initiator_vec;
>>>         sc_vector<Target>     target_vec;
>>>
>>>         sc_view(initiator_vec, &Initiator1::port).bind( sc_view
>>> (target_vec, &Target::xp) );
>>>
>>> In the above
>>>         sc_view(initiator_vec, &Initiator1::port)  creates a 
>>> vector-of-ports
>>>         sc_view(target_vec, &Target::xp)  creates a vector-of-exports
>>>         .bind()  does a vector-to-vector bind
>>>
>>> The semantics are very nice, but I am not particularly happy with the 
>> name 
>>> sc_view, because this is not suggestive of what is actually happening, 
>>> that is, gathering together a vector from a set of elements distributed 
> 
>>> across another vector. Is there a precedent for the name sc_view, 
>> Phillip? 
>>> How about something like sc_gather or sc_make_vector or sc_vectorize 
>>> instead?
>>
>> I don't have a strong feeling about the name sc_view.  Especially, since
>> I'm not particularly talented in given well-descriptive names.
>>
>>   The chosen name sc_view originates from the database world, where a
>> view is some kind of a "stored query", which can then be manipulated
>> more easily.  See e.g. http://en.wikipedia.org/wiki/Database_view
>>
>>   The cause is more or less the same here: With sc_view, you pre-select
>> a given member of the vector, without actually creating a "real"
>> sc_vector object.  Only accesses via this "view" are forwarded to the
>> _member object_ of the underlying vector element, instead of the element
>> itself.
>>
>> I could think of other names like
>>   sc_member[_view]()
>>   sc_children()
>>   sc_select[ion]()
>>
>> But as I said, I'm not really good at this. ;-)
>>
>> [snip get_elements]
>>
>>> Finally, in the special case of a vector-of-modules, it is possible to 
>>> pass extra arguments to the module constructor, e.g.
>>>
>>>         struct my_module: sc_module
>>>         {
>>>                  my_module(sc_module_name n, string weird_arg ) {...}
>>>                 ...
>>>         ...
>>>         sc_vector<my_module> my_vec;
>>>
>>>         struct my_module_creator
>>>         {
>>>                 my_module_creator( string arg ) : weird_arg(arg) {}
>>>
>>>                 my_module* operator() (const char* name, size_t)
>>>                 {
>>>                         return new my_module(name, weird_arg );
>>>                 }
>>>                 string weird_arg;
>>>         };
>>>         ...
>>>         my_vec.init(N, my_module_creator("The Creator"));
>>>
>>> This works, but creating the function object feels like having to jump 
>>> through hoops. I think regular users are going to find it confusing. 
> Can 
>>
>>> we do any clever tricks to make it easier to use?
>>
>> The reason for the complexity is two-fold:
>>
>>  - The Creator needs to receive the designated name for the element
>>    (and, for convenience, the current index)
>>  - The Creator may need to have a local state e.g. to store
>>    or generate additional arguments.
>>
>>   To use a custom Creator, the easiest/best solution depends on the
>> current situation.  If you have some globally accessible way to chose
>> your additional arguments, you may get away with a plain function:
>>
>> my_module* my_module_creator_func( const char* name, size_t i )
>> {
>>   return new my_module( name, WEIRD_ARG );
>> }
>> my_vec.init(N, my_module_creator_func );
>>
>>   Another quite simple way is to define a local member function in the
>> surrounding module and use sc_bind for the creator.  This way, you can
>> access the whole state of the owning module during creation and do all
>> kinds of nice stuff, like binding transport functions etc:
>>
>> SC_MODULE(parent)
>> {
>>   sc_vector< my_module >       my_vec;
>>   std::string                  weird_arg;
>>
>>   // member function as creator to use with sc_bind()
>>   my_module* init_element( const char* n, unsigned i )
>>   {
>>     my_module * mod = new my_module( n, weird_arg );
>>     mod->register_invalidate_direct_mem_ptr( this,
>>              &parent::invalidate_direct_mem_ptr, i );
>>     return mod;
>>   }
>>
>>   SC_CTOR(parent)
>>   {
>>     // use sc_bind, "this" + placeholders as creator
>>     // note: you may need to use sc_unamed::_1 in SystemC 2.3
>>
>>     my_vec.init( N, sc_bind( &parent::init_element, this, _1, _2 ) );
>>   }
>> };
>>
>> To me, the above is as easy as it can get in current C++.
>> Of course, C++0x lambdas will rock here in the future:
>>
>>     std::string weird_arg;
>>     my_vec.init( N,
>>                 [&]( const char*, size_t i)
>>                    { return new my_module( n, weird_arg ); }
>>                );
>>
>> I'm of course interested in any simpler approach to custom element
>> creation.  But I've spent some time on this issue and could not come up
>> with any easier solution for supporting arbitrary constructor 
> signatures.
>>
>>   I can see that this is not really part of C++/SystemC 101, but at
>> least it's consistent with other functor APIs in C++, like Compare (in
>> std::map and std::sort) or Function in std::for_each.
>>
>> Greetings from Oldenburg,
>> Philipp
>>
> 
> 
-- Philipp A. Hartmann Hardware/Software Design Methodology Group OFFIS Institute for Information Technology R&D Division Transportation · FuE-Bereich Verkehr Escherweg 2 · 26121 Oldenburg · Germany Phone/Fax: +49-441-9722-420/282 · PGP: 0x9161A5C0 · http://www.offis.de/ -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean.Received on Wed Nov 10 04:31:58 2010
This archive was generated by hypermail 2.1.8 : Wed Nov 10 2010 - 04:32:00 PST