vba – Factory class that uses reflection to instantiate objects based on the class name

In this SO contribution class dynamically select from string Alexander Platonov creates a function on the fly and then uses Application.Run() to instantiate an object by its class name. Eureka Reflection in VBA !! How evil! How inspiring !! This started my journey into the darkness.

My quest for power over reflection brings that ReflectionFactory Class. The default instance of this class changes itself by adding clauses to a Select Case, That way, I can instantiate the objects based on their class names New Keyword.

IAnimal: interface

Option Explicit

Public Function Speak() As String
End Function

Dog: class

Option Explicit
Implements IAnimal

Public Function Speak() As String
    Const Phrase As String = "Ruff Ruff Ruff"
    Debug.Print TypeName(Me); " says:"; """"; Phrase; """"
    Application.Speech.Speak Phrase
    Speak = Phrase
End Function

Private Function IAnimal_Speak() As String
    Speak
End Function

Cat: class

Option Explicit
Implements IAnimal

Public Function Speak() As String
    Const Phrase As String = "Meow Meow Meow"
    Debug.Print TypeName(Me); " says:"; """"; Phrase; """"
    Application.Speech.Speak Phrase
    Speak = Phrase
End Function

Private Function IAnimal_Speak() As String
    Speak
End Function

ReflectionFactory: class

Attribute VB_Name = "ReflectionFactory"
Attribute VB_PredeclaredId = True

Option Explicit
Private Const InsertAfter As String = "'" & "@Case ClassName InsertAfter"
Private Const vbext_ct_ClassModule As Long = 2

Public Sub AddClasses(ParamArray ClassNames() As Variant)
    Dim StartLine As Long
    Dim ClassName

    With getCodeModule
        For Each ClassName In ClassNames
            If Not .Find("Case*New " & ClassName, 1, 1, 1, 1, , , True) Then
                .Find InsertAfter, StartLine, 1, 1, 1
                .InsertLines StartLine + 1, getClassNameCase(CStr(ClassName))
            End If
        Next
    End With
End Sub

Public Sub Build()
    Dim VBComp As Object
    For Each VBComp In ThisWorkbook.VBProject.VBComponents
        If VBComp.Type = vbext_ct_ClassModule Then
            AddClasses VBComp.Name
        End If
    Next
End Sub

Private Function getCodeModule() As Object
    Set getCodeModule = ThisWorkbook.VBProject.VBComponents(TypeName(Me)).CodeModule
End Function

Private Function getClassNameCase(ByVal ClassName As String) As String
    getClassNameCase = vbTab & vbTab & "Case " & Chr(34) & ClassName & Chr(34) & ": Set CreateObject = New " & ClassName
End Function

Public Property Get CreateObject(ByVal ClassName As String) As Object
    Select Case ClassName
    '@Case ClassName InsertAfter
        Case "IAnimal": Set CreateObject = New IAnimal
        Case "MasterFactory": Set CreateObject = New MasterFactory
        Case "Dog": Set CreateObject = New Dog
        Case "Cat": Set CreateObject = New Cat

    End Select
End Property

exam

Sub ThisIsTooFun()
    Dim kitty As IAnimal, puppy As IAnimal, Animal As IAnimal
    ReflectionFactory.Build

    Set kitty = ReflectionFactory.CreateObject("Cat")
    Set puppy = ReflectionFactory.CreateObject("Dog")
    Set Animal = ReflectionFactory.CreateObject(Choose(WorksheetFunction.RandBetween(1, 2), "Cat", "Dog"))

    kitty.Speak
    puppy.Speak
    Animal.Speak
End Sub

Results

Immediate window results

In truth, I'll probably never use it, but boy, it was fun to get it started !!!

I'm still interested in your feedback. Do you think that it has any real applications? Hmmm… Java Bean too old. VBA Bean for use in a Visual Bean application.

Javascript Tree Class – Code checking stack exchange

I got caught in the trap of implementing my own data structure. I'm mainly looking for advice on how to make this code more idiomatic, but also about features that may be missing in this class or that are not required. I also want to think about how idiomatic the traverse function is and if there is a better way to implement it.

function Node(value = 0, children = ()) {
    this.value = value;
    this.children = children;
    this.parent = undefined;
}

Node.from = function(node) {
    let that = Object.assign(new Node(), node);
    that.parent = undefined;
    that.children = node.children.map(n => (Node.from(n), n.parent = that));
    return that;
};

Node.prototype.add = function(...children) {
    for (child of children) {
        child.parent = this;
        this.children.push(child);
    }
};

Node.Traversal = {
    BreadthFirst: 1,
    DepthFirst: 2
};

Node.prototype.traverse = function(callback, mode = Node.Traversal.BreadthFirst) {
    if (mode == Node.Traversal.BreadthFirst) {
        let nodes = (this);
        while (nodes.length > 0) {
            const current = nodes.shift();
            callback(current);
            nodes = nodes.concat(current.children);
        }
    } else if (mode == Node.Traversal.DepthFirst) {
        callback(this);
        this.children.forEach(n => n.traverse(callback, false));
    }
    return this;
};

Node.prototype.reduce = function(callback, initial, mode) {
    let acc = initial;
    this.traverse(n => acc = callback(acc, n), mode);
    return acc;
};

Node.prototype.every = function(callback) {
    return this.reduce((a, n) => a && callback(n), true);
};

Node.prototype.some = function(callback) {
    return this.reduce((a, n) => a || callback(n), false);
};

Node.prototype.find = function(callback, mode) {
    return this.reduce((a, n) => a || (callback(n)? n: false), false, mode);
};

Node.prototype.includes = function(value) {
    return this.some(n => n.value === value);
};

testing – Testable class / interface in embedded software, written in C ++

I'd like to get feedback on possible solutions for creating testable classes / interfaces.

In a normal non-embedded C ++ development, references / pointers and forward declarations can be used to obtain a dynamic polymorphism (see "Solution with References" below).

With the embedded restrictions, no dynamic memory, no virtual calls, no delete, No free etc. It seems that the only solution for achieving polymorphism is to use templates (see "Template Solution" below). This solution seems to be a good one, except that the code now always has to be in the header files and this can later lead to a slower compile time.

I wonder what other solutions are available that allow testable classes / interfaces:

  • When I'm on real hardware, I use the real driver implementation
  • In testing, I use the mock driver classes
  • I can easily switch between the real and the fake interface (Dependency Injection approach).

Solution with references

// Driver.h
class Driver {
public:
  virtual void doHardwareCall() = 0;
};

// DriverUser.h
class Driver;
class DriverUser {
  Driver &driver;

public:
  DriverUser(Driver &driver);

  void foo();
};

// DriverUser.cpp
DriverUser::DriverUser(Driver &driver) : driver(driver) {}
void DriverUser::foo() {
  driver.doHardwareCall();
}

// Test file
#include "DriverUser.h"

class MockDriver : public Driver {
  void doHardwareCall() override {
    std::cout << "MockDriver::doHardwareCall()" << std::endl;
  }
};

TEST(DriverUser, usingMockDriver) {
  MockDriver mockDriver;
  DriverUser driverUser(mockDriver);

  driverUser.foo(); // => outputs "MockDriver::doHardwareCall()"
}

Solution with templates

// Driver.h
class Driver {
public:
  void doHardwareCall();
};

// DriverUser.h
class Driver;

template 
class DriverUser {
  T &driver;
public:
  DriverUser(T &driver) : driver(driver) {}
  void foo() {
    driver.doHardwareCall();
  }
};

// Test file
#include "DriverUser.h"

class MockDriver : public Driver {
public:
  void doHardwareCall() {
    std::cout << "MockDriver::doHardwareCall()" << std::endl;
  }
};

TEST(DriverUser, usingMockDriver) {
  MockDriver mockDriver;
  DriverUser driverUser(mockDriver);

  driverUser.foo();
};

postgresql – Regex character class: print: in postgres

I'm trying to replicate an Oracle test condition that prevents characters from being printed in Postgres, and I'm at a loss. I think Postgres can handle: print: and: ascii: as synonymys?!?


select REGEXP_REPLACE('bla', '(^(:print:))', '(X)','g') ;
 regexp_replace 
----------------
 bla
(1 row)

select REGEXP_REPLACE('bla'||chr(10)||'bla', '(^(:print:))', '(X)','g') ;
 regexp_replace 
----------------
 bla(X)bla
(1 row)

select REGEXP_REPLACE('Ҕ', '(^(:print:))', '(X)','g') ;
 regexp_replace 
----------------
 (X)
(1 row)

select REGEXP_REPLACE('ñino', '(^(:print:))', '(X)','g') ;
 regexp_replace 
----------------
 (X)ino
(1 row)

Why should Ҕ and ñ be trapped in it?

Every guide is appreciated.

bitwise – Overload the C ++ enum class operators and enable the set check value

I usually use the class c ++ 11 enum instead of the old enumerations because many enumerations can contain the same value
As you know, they do not have the usual bitwise operators, so we should define them manually

In Windows this is already done for us with this macro in the header of windows.h:

DEFINE_ENUM_FLAG_OPERATORS

But then I came across another problem

If I use this enumeration as flags, I can use the bitwise operator | put many values ​​into the trap, but to test if the flag contains a value, I can not validate it with the bitwise operator.

if (flags & value) {...}

I could, however, write a template function like this for testing:

template 
constexpr bool has_value(T flags, T value)
{
    return (std::underlying_type_t)flags & (std::underlying_type_t)value;
}

but I really want to use the old format to test for values ​​in the flags
I've already found a solution for Github that wraps all selected emumes into a class called flags, and how the old ones were used, but with the type-security of enum classes

Since I do not want to use templates for this purpose and only want to specify operator & a bool value in if expressions, I have used another class that contains the enum value and can be converted to bool. I wrote this

#define OVERLOAD_ENUM_OPERATORS(x) 
class EnumBool##x 
{ 
    x enum_value; 
public: 
    constexpr EnumBool##x(const x e_val) : enum_value(e_val) {} 
    constexpr operator x() const { return enum_value; } 
    explicit operator bool() const { return (std::underlying_type_t)enum_value != 0; } 
}; 
inline constexpr EnumBool##x operator&(const x lhs, const x rhs) 
{ 
    return EnumBool##x((x)((std::underlying_type_t)lhs & (std::underlying_type_t)rhs)); 
} 
inline constexpr x operator|(const x lhs, const x rhs) 
{ 
    return (x)((std::underlying_type_t)lhs | (std::underlying_type_t)rhs); 
} 
inline constexpr x operator^(const x lhs, const x rhs) 
{ 
    return (x)((std::underlying_type_t)lhs ^ (std::underlying_type_t)rhs);
} 
inline constexpr x operator~(const x lhs) 
{ 
    return (x)(~(std::underlying_type_t)lhs);
} 
inline constexpr x& operator|=(x& lhs, const x rhs) 
{ 
    lhs = (x)((std::underlying_type_t)lhs | (std::underlying_type_t)rhs); 
    return lhs; 
} 
inline constexpr x& operator&=(x& lhs, const x rhs) 
{ 
    lhs = (x)((std::underlying_type_t)lhs & (std::underlying_type_t)rhs); 
    return lhs; 
} 
inline constexpr x& operator^=(x& lhs, const x rhs) 
{ 
    lhs = (x)((std::underlying_type_t)lhs ^ (std::underlying_type_t)rhs); 
    return lhs; 
} 
inline constexpr bool operator==(const x lhs, const x rhs) 
{ 
    return (std::underlying_type_t)lhs == (std::underlying_type_t)rhs; 
} 
inline constexpr bool operator!=(const x lhs, const x rhs) 
{ 
    return (std::underlying_type_t)lhs != (std::underlying_type_t)rhs; 
} 
inline constexpr bool operator>(const x lhs, const x rhs) 
{ 
    return (std::underlying_type_t)lhs > (std::underlying_type_t)rhs; 
} 
inline constexpr bool operator<(const x lhs, const x rhs) 
{ 
    return (std::underlying_type_t)lhs < (std::underlying_type_t)rhs; 
} 
inline constexpr bool operator>=(const x lhs, const x rhs) 
{ 
    return (std::underlying_type_t)lhs >= (std::underlying_type_t)rhs; 
} 
inline constexpr bool operator<=(const x lhs, const x rhs) 
{ 
    return (std::underlying_type_t)lhs <= (std::underlying_type_t)rhs; 
}

HaBangNet – Solid and reliable Enterprise Class VPS offering for Hong Kong CN2, USA and NL with low latency

HaBangNetWe guarantee you will love to host with us!

Website: https://www.HaBangNet.com
E-mail 24/7: cs@habangnet.com

HaBangNetWe are proud to offer web hosting services since 2010

>>> cPanel Partner NOC

>>> SolusVM exclusive distributor in China

>>> Hosting for businesses with the truth 24×7 house Technical support

HaBangNet Run multiple hosting locations around the world that you can choose to host your website.
Available VPS locations available: Europe, China, Hong Kong, Singapore, Germany, Lithuania and USA
New VPS location: Netherlands (Network connection – GTT / Telia / AMS-IX)

HaBangNet Set by experienced technical staff who works 24/7 and is available to solve your problem whenever you need us.

Only available at WHT, not listed on our website voucher.

The offer is for new customers and is not available for current customers and renewals.
Offer 1 coupon code: HBNVPS10F (Use this coupon code to get 10% off our standard VPS hosting service.)
Offer 2 coupon code: HBN2Y1OFF (Sign up for 2 years and get 3rd year hosting for free)

Our average make-ready time

All new registration at HaBangNet Within 1 to 24 hours you will receive new credentials.

HaBangNet VPS function

Intel Webhosting Server enterprise-class
Redundancy Setup
Free Cloud Base DNS
RAID-protected
Ultrafast I / O

Enterprise Class SSD and Cloud Storage
Premium BGP-optimized bandwidth
NO crowded environment
NO overselling
100% uptime SLA
Monitored network around the clock
* Internal DirectAdmin prices
* Internal cPanel / WHM prices
* Softaculous Auto Installer
* SpamExperts (INBound and OUTBound)
DDoS protection (Always on)
self-governing
Full root access
SolusVM VPS system control

VPS-HK CN2 (This package is not available on our website.)
2 vCore
2048 MB Ram
25 GB SSD memory
5 Mbps dedicated bandwidth
Premium China Telecom CN2 line
Direct routing to China, mainland

1 IPv4 (China Base IP)
Hong Kong Datacenter

$ 45.95 Monthly / Free Setup
More information
Join Now

VPS HKWert (This package is not available on our website.)
2 vCore
2048 MB Ram
50 GB of memory
5 Mbps dedicated bandwidth
1 IPv4
Hong Kong Datacenter

$ 25.95 Monthly / Free Setup
More information
Join Now

+Super high speed and low latency for Hong Kong servers within 40 ms to all over China with direct connection to ChinaNet Internet backbone+

VPS VZSEValue (This package is not available on our website.)
1 vCore
2048 MB Ram
25 GB of memory
500 GB Premium BGP Bandwidth
1 Gbps port
1 IPv4
Data center of the USA or the Netherlands

$ 5.95 Monthly / Free Setup
More information
Join Now

VPS VZSPValue (This package is not available on our website.)
4 vCore
6144 MB Ram
100 GB of memory
1000GB Premium BGP Bandwidth
1 Gbps port
1 IPv4
Data center of the USA or the Netherlands

$ 9.95 Monthly / Free Setup
More information
Join Now

Standard VPS Package Deal
The VPS listed here are hosted in our US data center
(Other locations VPS hosting, can be selected from our website or order form)

United States
Germany
Netherlands
Hong Kong
China (mainland
Singapore

VPS-One

2 core
2 GB RAM
50 GB cloud storage
1000GB Premium BGP Bandwidth
10 Gbps DDoS protection
1 Gbps port
1 IPv4
2 IPv6
Data center of the United States

$ 9.95 Monthly / Free Setup
More information
Join Now

VPS Two

2 core
4 GB RAM
75 GB of cloud storage
2000 GB Premium BGP Bandwidth
10 Gbps DDoS protection
1 Gbps port
1 IPv4
4 IPv6
Data center of the United States

$ 19.95 Monthly / Free Setup
More information
Join Now

VPS Three

4 core
6 GB RAM
100 GB cloud storage
3000 GB Premium BGP Bandwidth
10 Gbps DDoS protection
1 Gbps port
1 IPv4
6 IPv6
Data center of the United States

$ 29.95 Monthly / Free Setup
More information
Join Now

Control panel addon function

* Internal cPanel / WHM Cloud License (Admin) – $ 15.95 monthly
* Internal cPanel / WHM Cloud License (Pro) – $ 20.95 monthly
* cPanel / WHM with Softacuolus – Contact us for prices
* CyberPanel Enterprise License – Contact us for pricing
* DirectAdmin VPS License – $ 6.95 monthly
* Webuzo VPS license – 2 USD monthly

For more information about our Standard VPS or KVM VPS Hosting services can be found in our website

FAQ Which new customers always ask

* Does HaBangNet offer IPv6?
> IPv6 is only available in our standard VPS package for US and Europe.

* Do you have a Speedtest or an IP for Ping?
> Please visit our help desk for a speed test for download and upload speed.

* What is your I / O speed and limit the speed?
> We do not limit the I / O speed but offer Ultra Fast. Great for database hosting. Click here to view benchmarks

* The VPS is done.
> No. This VPS is completely self-managed.

* Can I know your uptime?
> Our uptime is provided by a 3rd party availability monitor at http://status.habangnet.com

* Limitations?
> NO GATE, NO Torrents, NO Illegal Activities, NO SPAM, No Bulk and / or Commercial Sending, NO DDoS Attacks, NO Brute Force and Hacking Activities.

* I have more questions about your VPS.
> For more information, visit our VPS FAQ website.

* What virtualization technology do you use for the VPS?
> This offer is on OpenVZ, KVM is available on our website.

* Which payment method do you accept?
> We accept Paypal, Paypal Express Checkout, Alipay, WeChat Pay, Bank Transfer, Local Bank Transfer in (China and Hong Kong).

Any questions? Send us your question via our online contact form.

Design Pattern – LinkedList using the node class in C ++

For practice, I implemented the Linked List data structure in C ++. The LinkedList.h used Node.h as a node. Create nodes and add them dynamically to the list. I have added function descriptions as comments directly above the functions.

I would like to receive comments and suggestions on code, algorithms (although not much is available), commenting style (I suppose my style of commenting is a bit poor), and everything that I've missed.

I include a basic one main Function if you want to execute the codes.

Node.h

template 
class Node {
  public:
    Node(const T& item);
    Node(const T& item, Node* nextNode);
    Node* next(void) const;
    void insertNext(Node* nextNode);
    Node* removeNext(void);
    T getData(void) const;
    void changeData(T& item);
  private:
    T data;
    Node* nextPtr;
};

/**
    *  @brief  Default constructor.
    *  @param  item  Data to be stored in the node.
    *  @return  void.
    *
    *  The constructor initializes variables.
    */
template 
Node::Node(const T& item) {
    data = item;
    nextPtr = nullptr;
}

/**
    *  @brief  Default constructor.
    *  @param  item  Data to be stored in the node.
    *  @param  nextNode   The next node of the node.
    *  @return  void.
    *
    *  The constructor initializes variables.
    */
template 
Node::Node(const T& item, Node* nextNode) {
    data = item;
    nextPtr = nextNode;
}

/**
    *  @brief  Returns the next node of the node.
    *  @param  void.
    *  @return  Node pointer of type T.
    */
template 
Node* Node::next(void) const {
    return nextPtr;
}

/**
    *  @brief  Inserts a node after the node.
    *  @param  nextNode  Pointer to the node to be inserted.
    *  @return  void.
    *
    *  Inserts the nextNode after the node and chains nextNode to the
    *  old next of the node.
    *
    */
template 
void Node::insertNext(Node* nextNode) {
    nextNode->nextPtr = nextPtr;
    nextPtr = nextNode;
}

/**
    *  @brief  Removes the nextPtr field of the node.
    *  @param  void.
    *  @return  Node of type T.
    *
    *  Removes the nextPtr field and equates it to nullptr.
    *  Returns the removed pointer.
    *
    */
template 
Node* Node::removeNext(void) {
    Node* removedPtr = nextPtr;
    nextPtr = nullptr;
    return removedPtr;
}

/**
    *  @brief  Retrieves the node data.
    *  @param  void.
    *  @return  Data of type T.
    */
template 
T Node::getData(void) const {
    return data;
}

/**
    *  @brief  Changes the node data.
    *  @param  item  The new data of the node.
    *  @return  void.
    */
template 
void Node::changeData(T& item) {
    data = item;
}

LinkedList.h

#include "Node.h"

template
class LinkedList {
  public:
    LinkedList(void); //c'tor
    LinkedList(const LinkedList& copyList); //copy c'tor
    ~LinkedList(void); //d'tor

    void insertAt(const T& item); //insert node at currPtr position
    void insertAfter(const T& item); //insert node after currPtr position
    void insertHead(const T& item); //insert node at headPtr position
    void insertTail(const T& item); //insert node at tailPtr position

    void removeAt(void); //remove the node at currPtr position
    void removeHead(void); // remove the head node

    void clear(void); //returns list to initial case
    void freeNode(Node* node); //free dynamic memory of a node

    std::size_t size(void) const; //size of the list
    bool empty(void) const; //the list is empty or not
    T nodeData(Node* node) const; //retrieve the input node data

    void moveToHead(void);//move currPtr to headPtr position
    void moveToTail(void); //move currPtr to tailPtr position
    void moveToPos(int n); //move currPtr to nth position
    int getPos(void) const; //the position of the currPtr

    void print(std::ostream& os); //prints the LinkedList and private variables

  private:
    void init(void); //initializes private variables
    Node* headPtr; //ptr to head node
    Node* tailPtr; //ptr to tail node
    Node* currPtr; //ptr to current node
    Node* prevPtr; //ptr to previous node
    std::size_t sizeL; //size of the linked list
    Node* newNode(const T& item); //allocate dynamic node
    Node* newNode(const T& item, Node* nextNode); //allocate dynamic node
};

/**
    *  @brief  Initializes class variables.
    *  @param  void.
    *  @return  void.
    *
    *  The init function sets all pointer to nullptr and sizeL to 0.
    */
template 
void LinkedList::init(void) {
    //ptr init
    headPtr = nullptr;
    tailPtr = nullptr;
    currPtr = nullptr;
    prevPtr = nullptr;
    //sizeL init
    sizeL = 0;
}

/**
    *  @brief  Default constructor.
    *  @param  void.
    *  @return  void.
    *
    *  The constructor uses init function to initialize variables.
    */
template 
LinkedList::LinkedList(void) {
    init();
}

/**
    *  @brief  Copy constructor.
    *  @param  copyList  The list to be copied.
    *  @return  void.
    *
    *  The copy constructor deepcopies the copyList to the object.
    */
template 
LinkedList::LinkedList(const LinkedList& copyList) {
    init();
    Node* tempPtr = copyList.headPtr;
    for(std::size_t cnt=0; cntnext();
    }
    moveToPos(copyList.getPos());
}

/**
    *  @brief  Default destructor.
    *  @param  void.
    *  @return  void.
    *
    *  The destructor uses clear function to release allocated memory.
    */
template 
LinkedList::~LinkedList(void) {
    clear();
}

/**
    *  @brief  Insert node to the LinkedList.
    *  @param  item  Data to be stored in the node.
    *  @return  void.
    *
    *  The insertAt function inserts a node to the location pointed by
    *  currPtr. The nodes following the currPtr are shifted whereas
    *  the nodes before the currPtr remain same.
    *
    *  If currPtr is pointing head or the LinkedList is empty,
    *  the function uses insertHead function.The LinkedList grows
    *  dynamically.
    *
    *  As a result of this function the currPtr points to the newly
    *  inserted node.
    */
template 
void LinkedList::insertAt(const T& item) {
    if((currPtr == headPtr) || empty()) {
        insertHead(item);
    } else {
        Node* tempPtr = newNode(item); //get a new node
        prevPtr->insertNext(tempPtr); //insert it after prevPtr
        currPtr = tempPtr; //arrange currPtr
        sizeL += 1; //sizeL increments
    }
}

/**
    *  @brief  Insert node to the LinkedList.
    *  @param  item  Data to be stored in the node.
    *  @return  void.
    *
    *  The insertAfter function inserts a node to the next of location
    *  pointed by currPtr. The nodes following the currPtr are shifted
    *  whereas the node currPtr and preceding nodes remain same.
    *
    *  If currPtr is pointing tail, the function uses insertTail
    *  function. The LinkedList grows dynamically.
    *
    *  If the LinkedList is empty, the function uses insertHead
    *  function.
    *
    *  As a result of this function the currPtr points to the newly
    *  inserted node.
    */
template 
void LinkedList::insertAfter(const T& item) {
    if(empty()) {
        insertHead(item);
    } else if(currPtr == tailPtr) {
        insertTail(item);
    } else {
        Node* tempPtr = newNode(item); //get a new node
        currPtr->insertNext(tempPtr); //insert it after prevPtr
        prevPtr = currPtr; //arrange prevPtr
        currPtr = tempPtr; //arrange currPtr
        sizeL += 1; //sizeL increments
    }
}

/**
    *  @brief  Insert node to the head of the LinkedList.
    *  @param  item  Data to be stored in the node.
    *  @return  void.
    *
    *  The insertHead function inserts a node to the head location
    *  of the LinkedList. The nodes following the headPtr are shifted.
    *
    *  As a result of this function the currPtr points to the newly
    *  inserted head node.
    */
template 
void LinkedList::insertHead(const T& item) {
    if(empty()) {
        Node* tempPtr = newNode(item); //get a new node
        headPtr = currPtr = tailPtr = tempPtr; /* arrange headPtr, currPtr,
                                                tailPtr */
        sizeL = 1; //sizeL is 1
    } else {
        Node* tempPtr = newNode(item, headPtr); //get a new node
        headPtr = currPtr = tempPtr; // arrange headPtr, currPtr
        prevPtr = nullptr; //arrange prevPtr
        sizeL += 1; //sizeL increments
    }
}

/**
    *  @brief  Insert node to the tail of the LinkedList.
    *  @param  item  Data to be stored in the node.
    *  @return  void.
    *
    *  The insertTail function inserts a node to the tail location
    *  of the LinkedList.
    *
    *  If the LinkedList empty, insertTail function uses insertHead function.
    *
    *  As a result of this function the currPtr points to the newly
    *  inserted tail node.
    */
template 
void LinkedList::insertTail(const T& item) {
    if(empty()) {
        insertHead(item);
    } else {
        Node* tempPtr = newNode(item); //get a new node
        prevPtr = tailPtr;
        tailPtr->insertNext(tempPtr); //insert it after tailPtr
        currPtr = tailPtr = tempPtr; //arrange currPtr, tailPtr
        sizeL += 1; //sizeL increments
    }
}

/**
    *  @brief  Remove the node pointed by currPtr.
    *  @param  void.
    *  @return  void.
    *
    *  The removeAt function removes the node pointed by currPtr. The node
    *  following is the new currPtr and is chained to prevPtr.
    *
    *  If the currPtr points to head, removeAt function uses
    *  removeHead function.
    *
    *  If currPtr points to tail, the preceding node is the new currPtr.
    *
    *  If the LinkedList becomes empty after removal,
    *  the variables are reset to initial states.
    *
    *
    */
template 
void LinkedList::removeAt(void) {
    if(empty()) {
        std::cerr << "The LinkedList empty. Can't remove current node." << 'n';
    } else if(size() == 1) {
        clear();
    } else if(currPtr == headPtr) {
        removeHead();
    } else if(currPtr == tailPtr) {
        freeNode(currPtr); //delete currPtr
        tailPtr = prevPtr; //arrange tailPtr
        sizeL -= 1; // decrement sizeL
        moveToTail(); // move currPtr to tailPtr
    } else {
        Node* tempPtr = currPtr->next(); //hold next of currPtr
        currPtr->insertNext(prevPtr); /* insert prevPtr to the next of currPtr.
                                        currPtr is out of list */
        freeNode(currPtr); //delete currPtr
        currPtr = tempPtr; //arrange currPtr
        sizeL -= 1;
    }

}

/**
    *  @brief  Remove the node pointed by headPtr.
    *  @param  void.
    *  @return  void.
    *
    *  The removeHead function removes the node pointed by headPtr. The node
    *  following is the new headPtr.
    *
    *  If the currPtr points to head, currPtr is updated to new headPtr.
    *
    *  If the prevPtr points to head, prevPtr is updated as nullptr.
    */
template 
void LinkedList::removeHead(void) {
    if(empty()) {
        std::cerr << "The LinkedList empty. Can't remove head  node." << 'n';
    } else if(size() == 1) {
        clear();
    } else if(currPtr == headPtr) {
        Node* tempPtr = headPtr->next(); //hold next of headPtr
        freeNode(headPtr); //delete headPtr
        headPtr = tempPtr; //arrange headPtr
        sizeL -= 1; //decrements sizeL

        currPtr = headPtr; //arrange currPtr
    } else if (prevPtr == headPtr) {
        Node* tempPtr = headPtr->next(); //hold next of headPtr
        freeNode(headPtr); //delete headPtr
        headPtr = tempPtr; //arrange headPtr
        sizeL -= 1; //decrements sizeL

        prevPtr = nullptr; //arrange currPtr
    } else {
        Node* tempPtr = headPtr->next(); //hold next of headPtr
        freeNode(headPtr); //delete headPtr
        headPtr = tempPtr; //arrange headPtr
        sizeL -= 1; //decrements sizeL
    }
}

/**
    *  @brief  Returns the LinkedList to its initial state.
    *  @param  void.
    *  @return  void.
    *
    *  The clear function deletes all nodes in the LinkedList and returns
    *  all variables to their initial state.
    */
template 
void LinkedList::clear(void) {
    moveToHead();
    Node* tempPtr;
    for(std::size_t cnt=0; cntnext();  //hold next of currPtr
        freeNode(currPtr); //delete currPtr
        currPtr = tempPtr; //arrange currPtr
    }
    init();
}

/**
    *  @brief  Releases allocated dynamic memory of a node.
    *  @param  node  The pointer to the target node.
    *  @return  void.
    */
template 
void LinkedList::freeNode(Node* node) {
    delete node;
}

/**
    *  @brief  Returns the LinkedList size.
    *  @param  void.
    *  @return  size
    */
template 
std::size_t LinkedList::size(void) const {
    return sizeL;
}

/**
    *  @brief  Returns true if the LinkedList empty,
    *  @brief  false otherwise.
    *  @param  void.
    *  @return  Boolean value true or false.
    */
template 
bool LinkedList::empty(void) const {
    return (sizeL == 0);
}

/**
    *  @brief  Returns the data stored in the specified node.
    *  @param  node  The target node.
    *  @return  The data stored in the node of type T.
    */
template 
T LinkedList::nodeData(Node* node) const {
    return node->getData();
}

/**
    *  @brief  Move currPtr to headPtr.
    *  @param  void.
    *  @return  void.
    *
    *  The moveToHead function moves currPtr to headPtr.
    */
template 
void LinkedList::moveToHead(void) {
    currPtr = headPtr;
    prevPtr = nullptr;
}

/**
    *  @brief  Move currPtr to tailPtr.
    *  @param  void.
    *  @return  void.
    *
    *  The moveToTail function uses moveToHead function with
    *  parameter (sizeL - 1) to move currPtr to tailPtr.
    */
template
void LinkedList::moveToTail(void) {
    moveToPos(sizeL - 1);
}

/**
    *  @brief  Move currPtr to nth node of the LinkedList.
    *  @param  n  Position of the target node where n € (0 , sizeL - 1).
    *  @return  void.
    *
    *  The moveToPos function iterates over the LinkedList nodes to move
    *  currPtr to the nth node of the LinkedList. n is in
    *  the range of (0 , sizeL - 1).
    *
    *  The moveToPos function uses moveToHead function to move currPtr
    *  to headPtr.
    */
template 
void LinkedList::moveToPos(int n) {
    moveToHead();
    for(int cnt=0; cntnext();
    }
}

/**
    *  @brief  Returns the position of the currPtr
    *  @param  void.
    *  @return  Integer representing position of the currPtr.
    *
    *  The getPost function iterates over the list until reaches the currPtr.
    *  Then returns the position of the currPtr as int.
    */
template 
int LinkedList::getPos(void) const {
    Node* tempPtr = headPtr;
    int cnt;
    for(cnt=0; tempPtr!=currPtr; cnt++) {
        tempPtr = tempPtr->next();
    }
    return cnt;
}

/**
    *  @brief  Creates a dynamic Node of type T.
    *  @param  item  Data to be stored in the new node.
    *  @return  void.
    *
    *  Returns a pointer to node created dynamically. The new node's data is
    *  item of type T. The new node's next pointer is nullptr.
    */
template 
Node* LinkedList::newNode(const T& item) {
    Node* tempPtr = nullptr;
    tempPtr = new Node(item);
    if(tempPtr == nullptr) {
        std::cerr << "Memory allocation for new node is failed" << 'n';
        return nullptr;
    } else {
        return tempPtr;
    }
}

/**
    *  @brief  Creates a dynamic Node of type T.
    *  @param  item  Data to be stored in the new node.
    *  @param  nextNode  The next node of the new node.
    *  @return  void.
    *
    *  Returns a pointer to node created dynamically. The new node's data is
    *  item of type T. The new node's next pointer is nextNode of type T.
    */
template 
Node* LinkedList::newNode(const T& item, Node* nextNode) {
    Node* tempPtr = nullptr;
    tempPtr = new Node(item, nextNode);
    if(tempPtr == nullptr) {
        std::cerr << "Memory allocation for new node is failed" << 'n';
        return nullptr;
    } else {
        return tempPtr;
    }
}

/**
    *  @brief  Prints the LinkedList nodes together with private variables.
    *  @param  os  The printing medium.
    *  @return  void.
    */
template 
void LinkedList::print(std::ostream& os) {
    os << "Class Variables:n";
    //headPtr
    if(headPtr == nullptr)
        os << "headPtr: " << "nullptr" << " | ";
    else
        os << "headPtr: " << headPtr << ' '  << nodeData(headPtr) << " | ";
    //prevPtr
    if(prevPtr == nullptr)
        os << "prevPtr: " << "nullptr" << 'n';
    else
        os << "prevPtr: " << prevPtr << ' '  << nodeData(prevPtr) << 'n';
    //tailPtr
    if(tailPtr == nullptr)
        os << "tailPtr: " << "nullptr" << " | ";
    else
        os << "tailPtr: " << tailPtr << ' ' << nodeData(tailPtr) << " | ";
    //currPtr
    if(currPtr == nullptr)
        os << "currPtr: " << "nullptr" << 'n';
    else
        os << "currPtr: " << currPtr << ' '<< nodeData(currPtr) << 'n';

    //sizeL
    os << "sizeL: " << sizeL << 'n';
    Node* tempPtr = headPtr;
    for(std::size_t cnt=0; cnt ";
        tempPtr = tempPtr->next();
    }
    os << 'n';
}

Test Code

#include "LinkedList.h"

int main() {
    LinkedList MyList;
    for(int i=1; i<7; i++)
        MyList.insertAfter(i);
    MyList.print(std::cout);

    MyList.moveToPos(3);
    MyList.print(std::cout);

    MyList.removeAt();
    MyList.print(std::cout);

    MyList.insertAt(9);
    MyList.print(std::cout);

    MyList.insertAfter(10);
    MyList.print(std::cout);

    MyList.removeAt();
    MyList.print(std::cout);

    MyList.removeAt();

    MyList.moveToPos(3);
    MyList.print(std::cout);
    std::cout << "********************" << 'n';
    LinkedList CopiedList(MyList);
    CopiedList.print(std::cout);
    std::cout << "********************" << 'n';

    MyList.moveToHead();
    MyList.print(std::cout);
    MyList.removeHead();
    MyList.removeHead();
    MyList.removeAt();
    MyList.removeAt();
    MyList.removeAt();
    MyList.removeAt();

    MyList.print(std::cout);
    std::cout << "********************" << 'n';
    CopiedList.print(std::cout);
    std::cout << "********************" << 'n';

    for(int i=1; i<6; i++)
        MyList.insertHead(i);
    MyList.print(std::cout);
}
```

dnd 3.5e – What does Divine Soul mean in the contemplative prestige class?

"Your grade level" in this case refers to "levels in the contemplative class". So a 10th level minister and a 10th level contemplative will have a spell resistance of 10 + 15 = 25.

If it had been the level of the character rather than the levels in the contemplative class, it would have been called "the overall level of the contemplative" or "the level of the contemplative," rather than "its class level," which refers specifically to levels in the contemplative class Class.