Algorithm Library Design in C ++ IV (genvoca Architecture)

Source: Internet
Author: User
Tags wrappers
Genvoca Architecture

Genvoca is a software architecture. Similar to the policy-based architecture, the final product of genvoca is made up of various components, but the organization is different.

In the policy-based architecture, components are added to the host class as specific policy implementations to implement corresponding functions, while components in genvoca are used as wrappers (layers) on top of a more basic components adding functionality to it.

In my opinion, from the implementation of the list given in the original article, genvoca has different layers than the policy-based architecture, and the upper layer requires different implementation at the lower layer. For example, layer B needs the following C to implement, and the implemented B can be provided to the upper-Layer A as the implementation.

 
R: A | B [R] S: C [R] | D [s] | E [R, S]
 
R can be implemented by a, or by a combination of B and R.
 
S can be implemented by a certain implementation of C and R.
Genvoca instance: List

Is a list feature map. The feature is from the user's perspective. The user assembles the parameters to be provided by the list.

Necessary features

What kind of data does list need to manipulate?

How does list hold data? It is held by reference or by means of deep copy.

Do we use polymorphism for data operations?

Optional features

Do you need a variable record length?-> If the data type to be long is int short or long

Do you need tracing? Does it mean that we want to track the process and print the process information?

To design a genvoca architecture, consider the following steps:
    • Determine the main responsibilities mentioned in the Special diagram and the main functions to be provided. For list:
      • Data Storage
      • Data Copying
      • Data destruction (note that this corresponds to the feature graph. If you select copy to hold data or owned reference, you must delete the data yourself. Otherwise, empty Delete is not required)
      • Dynamic type check (for monomorphism)
      • Length counter
      • Tracing
    • Determine the component group:
      • Basiclist: ptrlist // indicates the policy component on the left, and categories: Components indicates different implementation policies on the right.
      • Copier: polymorphiccopier, monomorphiccopier, emptycopier
      • Desroyer: elementdestroyer, emptydestroyer
      • Typechecker: dynamictypechecker, emptytypechecker
      • Counter: lengthlist
      • Tracing: tracedlist
    • Are you sure you want to use the dependency 'use' dependencies between component categories.

    • Sort the categories into a layered architecture. Get the specific architecture. The bottom-layer copier, destoryer, and typechecker are used as config.

The component categories that do not depend on other categories are grouped into the bottomConfigurationrepository(ConfigFor short) layer category.

Tracing and counter are optional groups.

My note clearly shows the overall architecture design of the list.

Basiclist (actually implemented using the ptrlist class) has three policies: copier, destoryer, and typecheker. Different policies are selected to combine different lists. It is actually a policy-based design.

Then counter uses basiclist

Use the template inheritance method.

<Typename base>

Class derived: public Base

By taking the basiclist as the template parameter and inheriting it, the counter can reuse the basiclist. At the same time, it provides its own basiclist length counters and modifies the corresponding operation to maintain the length count.

Tracing uses counter, which is at the top and inherits counter in the same way, and then modifies the information printed during the corresponding operation.

    • Write down genvoca Grammar
List: tracedlist [optcounterlist] | usage: lengthlist [basiclist] | basiclistbasiclist: ptrlist [config] config: copier: Role | role | includestroyer: elementdestroyer | emptydestroyer typechecker: dynamictypechecker | emptytypechecker elementtype: [elementtype] lengthtype: int | short | long |...
Implementation Details

You can customize a config that meets your needs.

Struct tracedintlistconfig {typedef int elementtype; typedef const elementtype struct; typedef struct <elementtype> copier; typedef elementdestroyer <elementtype> destroyer; typedef dynamictypechecker <elementtype> typechecker;Typedef tracedlist <ptrlist <tracedintllistconfig> finallisttype;}; Typedef tracedintlistconfig: finallisttype tracedintlist;
 
Here, we should note that the cyclical dependency of template parameters appears. In this way, a specific final list type can be provided.
 
Note: In fact, this config should not be provided to the user. These parameters ultimately determine the list type, but should not be set by the user. This is a relatively internal config, for example, destroyer is transparent to users.
 
The user may setMonomorphiccopierAndEmptydestroyer may cause memory leakage errors.
 
An abstraction layer should be separated. As long as the user declares that I use copy to hold data, or that I use ownwed refernce, the internal database decides to use elementdestroyer.
 
If you declare that you want to use external refernce to hold data, the internal database will decide to use emptydestroyer, without the displayed Delete, that is, I am not responsible for data release.
The following will show how to add this abstraction layer, the so-calledGeneratorMethod to allow users to set parameters at a higher level.
 
 
 
OK. We first implement a basic ptrlist, which is the most basic list. It has many policy parameters. The implementation of specific policies is provided in config.
Template < Class Config _> Class Ptrlist { Public : // Export config    Typedef config _ config;    Private : // Retrieve the needed types from the Repository Typedef typename config: elementtype; typedef typename config: delimiter; typedef typename config: copier delimiter; typedef typename config: destroyer; typedef typename config: typechecker; Typedef typename config: finallisttype;    // Data members Elementtype * head _; finallisttype * tail _; // Note: Not ptrlist * But finallisttype *  Public : Ptrlist (elementargumenttype & H, finallisttype * T = 0): Head _ (0), tail _ (t) {set_head (h );}~ Ptrlist (){ Destroyer: Destroy (Head _) ;} Void Set_head (elementargumenttype & H ){Typechecker: Check (h ); Head _ = Copier: Copy (h ); } Elementtype & head (){ Return * Head _;} Void Set_tail (finallisttype * t) {tail _ = T;} finallisttype * tail () Const { Return Tail _;}};

 

// Use the most basic list

Template <ClassList>VoidPrint_list (list * l) {STD: cout <"[";For(; L = L-> tail () STD: cout <L-> head () <" "; STD: cout <"] \ N";} Template <ClassList>VoidPush_front (typename list: elementargumenttype & E, list * & L) {L =NewList (E, L );}IntMain () {typedef listconfig: finallisttype list; list * ls = 0; push_front (1, ls); push_front (2, ls); push_front (3, ls ); print_list (LS );// Prints "3 2 1"}

Note that some operations are transferred to other classes in the list implementation, that is, some policy parameters, such as copier and destoyer.

Template <Class Elementtype> Struct Monomorphiccopier { Static Elementtype * Copy ( Const Elementtype & E ){ Return   New Elementtype (e) ;}}; template < Class Elementtype> Struct Polymorphiccopier { Static Elementtype * Copy ( Const Elementtype & E ){ Return E. Clone ();// Polymorphic copy using } // Virtual member function clone () }; Template < Class Elementtype> Struct Emptycopier { Static Elementtype * Copy (elementtype & E ){ // Note: Not const      Return & E; // No copy }}; Template < Class Elementtype> Struct Elementdestroyer { Static  Void Destroy (elementtype * E) {Delete E ;}}; template < Class Elementtype> Struct Emptydestroyer { Static   Void Destroy (elementtype * E ){} // Do nothing }; Template < Class Elementtype> Struct Dynamictypechecker { Static   Void Check ( Const Elementtype & E) {assert (typeid (e) = typeid (elementtype) ;}}; template < Class Elementtype> Struct Emptytypechecker { Static   Void Check ( Const Elementtype & E ){}};
 
 
 
At last, the Laer at the upper layer adopts the inheritance-based wrappers implementation. Such as lengthlist
Template < Class Basiclist> Class Lengthlist: Public Basiclist { Public :// Export config Typedef typename basiclist: config; Private : // Retrieve the needed types from the Repository Typedef typename config: elementtype; typedef typename config: too large; typedef typename config: finallisttype; lengthtype length _; lengthtype timeout () Const { Return Tail ()? Tail ()-> length () + 1: 1 ;} Public : Lengthlist (elementargumenttype & H, finallisttype * T = 0): basiclist (h, t) {length _ = compute_length ();}Void Set_tail (finallisttype * t) {basiclist: set_tail (t); length _ = compute_length ();} lengthtype length () Const { Return Length _;}};

Generators

The following provides an abstract method for setting interfaces for users.

 
Enum ownership {ext_ref, own_ref, CP}; Enum morphology {mono, poly}; Enum counterflag {with_counter, no_counter}; Enum tracingflag {with_tracing, no_tracing };
 
The preceding figure shows the list configuration parameters that users need to know.
 
Template <bool condition, class then, class else> struct if {typedef then ret;}; Template <class then, class else> struct If <false, then, else> {typedef else ret ;};

The above is a kind of technique for selecting types during compilation by using template-specific features.

The following is the implementation of the specific generator:

Template <Class Elementtype _, ownership = CP, morphology = mono, counterflag counter_flag = no_counter, tracingflag tracing_flag = no_tracing, Class Lengthtype _ = Int > Class List_generator { Public : // Forward Declaration of the configuration Repository    Struct Config; Private : // Define the constants used for Type Selection    Enum {Is_copy = ownership = CP, region = ownership = own_ref, is_mono = morphology = mono, has_counter = counters = with_counter, does_tracing = tracing_flag = with_tracing }; // Select the components Typedef typename If <is_copy | is_own_ref, elementdestroyer <elementtype _>, struct <elementtype _>: Ret destroyer _; typedef typename If <is_mono, dynamictypechecker <elementtype _>, emptytypechecker <elementtype _>: Ret typechecker _; typedef typename If <is_copy, typename If <is_mono, role <elementtype _>, polymorphiccopier <elementtype _>: Ret, emptycopier <elementtype _>: Ret copier _; typedef typename If <is_copy, Const Elementtype _, elementtype _>: Ret elementargumenttype _;// Define the list type Typedef ptrlist <config> basiclist; typedef typename If  Public : // Return the final list type Typedef list ret; // Define the configuration Repository    Struct Config {typedef elementtype _ elementtype; typedef delimiter _ delimiter; typedef copier _ copier; typedef destroyer _ destroyer; typedef typechecker _ typechecker; typedef delimiter _ lengthtype; typedef RET finallisttype ;};};

 

 
You can use this to configure the list
 
Ypedef list_generator <int, CP, Mono, no_counter, with_tracing >:: RET tracedintlist;

If you do not need traing

Typedef list_generator <int>: Ret intlist;

 

Finally, shape, square, and circle use virtual functions, because we need dynamic polymorphism to operate on the column graphics.

The list does not use virtual functions, but the inheritance class only overwrites the parent class, because dynamic polymorphism is not used for the list, and the subclass pointer is directly used.

In addition, the currentProgramIt only demonstrates the idea of genvoca architecture, but there are still many problems. For example, if the current list is copied and constructed or the owned reference, its destructor can only parse the first element of a list, other

The element cannot be destructed. You need to write a destory function outside the class, destory (list * l );
 
 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.