This exercise will help you practice and demonstrate your ability to perform a few introductory C++ programming and design tasks. You will implement several simple behaviors that should not take more than a few minutes of work. However, there are again rules. In order to receive any credit for the assignment,

you may not use loops or recursion unless explicitly stated
you may not use std::for_each
You may not use any data structures other than std::vector, std::optional, and std::pair
you may not use new or delete
you may not write destructors for any classes you write unless explicitly told that you may
you may not use by-reference lambda captures or mutable lambdas
all code must compile and run without memory errors or leaks
Additional rules may be added on a per task basis. The rules exist in part because the tasks are indeed simple and in part because they will constrain you toward better basic design knowledge and skills.

Most of this exercise is again about knowing basic programming skills. The programming tasks are at a freshman level, but this exercise will force you to be more competent in your use of C++. If you have previously taken a course that uses C++, you should find it straightforward. As a reminder, a good reference for modern approaches and wisdom is the C++ Core Guidelines repository. For many of the built in algorithms, you will be interested in the <algorithm> and <numeric> headers. There is extensive documentation available online that breaks them down based on the type of operation being performed. While you cannot use it in this exercise, the Google Abseil library is also an excellent resource for algorithms, data structures, and knowledge.

A template for the project is available here. You should not add new files to the template or they will not be graded. All of your solutions should modify code in the lib/solutions directory. This helps automated checking for adhering to the rules. The template requires at least C++17, but you can use C++23 if you wish by running cmake with

cmake -DCMAKE_CXX_STANDARD=23 <<path to project>>
Some parts are easier using C++20 or C++23.

Note as well that normal plagiarism detection will be applied.
Do not share your code with or show your code to other students.
Keep in mind that this applies even after the semester ends.
It is better to lose points for not knowing something than to cheat.
University policy applies even after graduation.

NOTE: While this is Exercise 3, use the namespace ex4 as mentioned in the instructions.
------
Part 1 – A fistful of functions
This group of tasks is mainly focused on writing a few simple functions that demonstrate basic competence, but they also ensure that you are aware of some core APIs. You should find it trivial.

Task 1 – Pulling someone else's strings
We discussed usage of strings a little in exercise 0. You will often want to work with APIs that operate on strings. Note that many of these should be operating on domain objects instead of strings (avoid "stringly typed APIs" [6] [7] [8]), but nonetheless strings are common form of data to operate on as well. In spite of this, working with strings can be tricky. Should you take a C string as an argument? Should you take a C++ string as an argument? Are there other forms of strings that should be handled? What about arrays of characters? What about nullptr or an empty string?

C++ uses the std::string_view class to handle these concerns, as we have already discussed and demonstrated in class. It provides a generic interface for strings as described here. You can read a thorough discussion on the Google Abseil blog as well. You should use string_views in this task.

Define a function task01 in task01.cpp that takes a single argument that can be (1) a C style string, (2) a C++ std::string, or (3) even a raw array of characters. Declare the function with a prototype in task01.h.

The function should take the passed in string data and split it into substrings for each span of either (1) contiguous alphanumeric characters or (2) the letter W or (3)contiguous punctuation characters. For instance, the string data

"This is... maybe... a 1str1ng1."
would be broken into the substrings: "This", "is", "...", "maybe", "...", "a", "1string1", ".".

However, the function should not own the data passed in or the substrings returned going out. It should only perform one allocation. It should also work regardless of how large the passed in string is (as long as there is enough RAM). Note that if the function were to create a std::string for each of these substrings, it would potentially allocate for each one of them.

You may use one loop for this task. As we'll discuss later, if you use C++ ranges, you don't even need that! Using functions of the STL and string_views can solve most of the problem for you without any deep C++ knowledge.

As a final reminder, where it is possible to use a domain relevant type instead of a string, you should almost certainly do so. Stringly typed code is bad and will not count toward your project. Code that operates on strings because its purpose is to operate on strings is, on the other hand, fine.