Skip to content

Commit

Permalink
Add C++ exercises (#46)
Browse files Browse the repository at this point in the history
* Update instructions to add more clarity

* Initial import of exercise files

* Initial devcontainer config for cmake

* Updating container config

* Completing exercises

* Update main README
  • Loading branch information
colindembovsky authored Oct 2, 2024
1 parent 2cf6be7 commit b2c4e00
Show file tree
Hide file tree
Showing 33 changed files with 1,131 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
]
}
},
"postCreateCommand": "cd ./completesolution/node; npm install; cd ../../; dotnet restore ./completesolution/dotnet/MinimalAPI.sln; dotnet restore ./exercisefiles/dotnet/MinimalAPI.sln"
"postCreateCommand": "sudo ./.devcontainer/scripts/install-cmake.sh; cd ./completesolution/node; npm install; cd ../../; dotnet restore ./completesolution/dotnet/MinimalAPI.sln; dotnet restore ./exercisefiles/dotnet/MinimalAPI.sln"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
Expand Down
22 changes: 22 additions & 0 deletions .devcontainer/scripts/install-cmake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------

set -e

echo "Installing apt packages..."
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get -y install build-essential cmake cppcheck valgrind clang lldb llvm gdb
apt-get autoremove -y
apt-get clean -y
rm -rf /var/lib/apt/lists/*

echo "Installing vcpkg..."
export VCPKG_ROOT=/usr/local/vcpkg
export VCPKG_DOWNLOADS=/usr/local/vcpkg-downloads
export PATH="${PATH}:${VCPKG_ROOT}"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
"${DIR}/install-vcpkg.sh" vscode
85 changes: 85 additions & 0 deletions .devcontainer/scripts/install-vcpkg.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------

set -e

USERNAME=${1:-"vscode"}

. /etc/os-release

# Add to bashrc/zshrc files for all users.
updaterc() {
echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
echo -e "$1" >> /etc/bash.bashrc
fi
if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
echo -e "$1" >> /etc/zsh/zshrc
fi
}

# Run apt-get if needed.
apt_get_update_if_needed() {
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
echo "Running apt-get update..."
apt-get update
else
echo "Skipping apt-get update."
fi
}

# Check if packages are installed and installs them if not.
check_packages() {
if ! dpkg -s "$@" > /dev/null 2>&1; then
apt_get_update_if_needed
apt-get -y install --no-install-recommends "$@"
fi
}

export DEBIAN_FRONTEND=noninteractive
export VCPKG_FORCE_SYSTEM_BINARIES=1

# Install additional packages needed by vcpkg: https://github.com/microsoft/vcpkg/blob/master/README.md#installing-linux-developer-tools
check_packages build-essential tar curl zip unzip pkg-config bash-completion ninja-build

# Setup group and add user
umask 0002
if ! cat /etc/group | grep -e "^vcpkg:" > /dev/null 2>&1; then
groupadd -r "vcpkg"
fi
usermod -a -G "vcpkg" "${USERNAME}"

# Start Installation
# Clone repository with ports and installer
mkdir -p "${VCPKG_ROOT}"
mkdir -p "${VCPKG_DOWNLOADS}"
git clone --depth=1 \
-c core.eol=lf \
-c core.autocrlf=false \
-c fsck.zeroPaddedFilemode=ignore \
-c fetch.fsck.zeroPaddedFilemode=ignore \
-c receive.fsck.zeroPaddedFilemode=ignore \
https://github.com/microsoft/vcpkg "${VCPKG_ROOT}"

## Run installer to get latest stable vcpkg binary
## https://github.com/microsoft/vcpkg/blob/7e7dad5fe20cdc085731343e0e197a7ae655555b/scripts/bootstrap.sh#L126-L144
"${VCPKG_ROOT}"/bootstrap-vcpkg.sh

# Add vcpkg to PATH
updaterc "$(cat << EOF
export VCPKG_ROOT="${VCPKG_ROOT}"
if [[ "\${PATH}" != *"\${VCPKG_ROOT}"* ]]; then export PATH="\${PATH}:\${VCPKG_ROOT}"; fi
EOF
)"

# Give read/write permissions to the user group.
chown -R ":vcpkg" "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}"
chmod g+r+w+s "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}"
chmod -R g+r+w "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}"

# Enable tab completion for bash and zsh
VCPKG_FORCE_SYSTEM_BINARIES=1 su "${USERNAME}" -c "${VCPKG_ROOT}/vcpkg integrate bash"
VCPKG_FORCE_SYSTEM_BINARIES=1 su "${USERNAME}" -c "${VCPKG_ROOT}/vcpkg integrate zsh"
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,40 @@ FodyWeavers.xsd
*.sln.iml
.idea/

# C++ excludes

# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

build

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ Run:
**For Python**
- [Install Python](https://www.python.org/downloads/)

**For C++**
- [Install cmake](https://cmake.org/download/)

## Labs instructions

- [Node Server](./exercisefiles/node/README.md)
Expand All @@ -90,6 +93,7 @@ Run:
- [Java Quarkus](./exercisefiles/quarkus/README.md)
- [Python Data Engineer](./exercisefiles/dataengineer/README.md)
- [Python Data Scientist](./exercisefiles/datascientist/README.md)
- [C++](./exercisefiles/c++/README.md)

## Challenges instructions

Expand Down
13 changes: 13 additions & 0 deletions completesolution/c++/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.14)

project(OctoConverter
VERSION 1.0.0
LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

enable_testing()

add_subdirectory(src)
add_subdirectory(test)
10 changes: 10 additions & 0 deletions completesolution/c++/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_subdirectory(converters)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE converters)

set_target_properties(
main
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}"
)
11 changes: 11 additions & 0 deletions completesolution/c++/src/converters/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Build a library "converters" with all included files
add_library(
converters
distance.cpp
distance.h
temperature.cpp
temperature.h
weight.cpp
weight.h
types.h
)
105 changes: 105 additions & 0 deletions completesolution/c++/src/converters/distance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "distance.h"
#include <iostream>
#include <unordered_map>

namespace /* private */ {
std::string getDistanceUnitSign(DistanceUnit unit)
{
std::unordered_map<DistanceUnit, std::string> unitSigns = {
{DistanceUnit::Meters, "m"},
{DistanceUnit::Feet, "ft"},
{DistanceUnit::Yards, "yd"}
};

return unitSigns.at(unit);
}
} // namespace private

namespace DistanceConversion
{
void startFlow()
{
double sourceValue = getSourceValue();
DistanceUnit from = getDistanceUnit("source");
DistanceUnit to = getDistanceUnit("target");

double targetValue = convertDistance(sourceValue, from, to);

std::cout << sourceValue << getDistanceUnitSign(from) << " is " << targetValue << getDistanceUnitSign(to) << std::endl;
}

double getSourceValue()
{
double value;
std::cout << "Enter the value to be converted: ";
std::cin >> value;
return value;
}

DistanceUnit getDistanceUnit(const std::string_view &sourceOrTarget)
{
int choice;
std::cout << "Select " << sourceOrTarget << " distance unit:\n";
std::cout << "[1] Meters\n";
std::cout << "[2] Feet\n";
std::cout << "[3] Yards\n";
std::cout << "Enter choice: ";
std::cin >> choice;

switch (choice)
{
case 1:
return DistanceUnit::Meters;
case 2:
return DistanceUnit::Feet;
case 3:
return DistanceUnit::Yards;
default:
return DistanceUnit::Meters; // Default to Meters
}
}

double convertDistance(double value, DistanceUnit from, DistanceUnit to)
{
if (from == to)
{
return value;
}

if (from == DistanceUnit::Meters)
{
if (to == DistanceUnit::Feet)
{
return value * 3.28084;
}
else if (to == DistanceUnit::Yards)
{
return value * 1.09361;
}
}
else if (from == DistanceUnit::Feet)
{
if (to == DistanceUnit::Meters)
{
return value / 3.28084;
}
else if (to == DistanceUnit::Yards)
{
return value / 3.0;
}
}
else if (from == DistanceUnit::Yards)
{
if (to == DistanceUnit::Meters)
{
return value / 1.09361;
}
else if (to == DistanceUnit::Feet)
{
return value * 3.0;
}
}

return 0;
}
}
21 changes: 21 additions & 0 deletions completesolution/c++/src/converters/distance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef DISTANCE_H
#define DISTANCE_H

#include <string>

enum class DistanceUnit
{
Meters,
Feet,
Yards
};

namespace DistanceConversion
{
void startFlow();
double getSourceValue();
DistanceUnit getDistanceUnit(const std::string_view &sourceOrTarget);
double convertDistance(double value, DistanceUnit from, DistanceUnit to);
}

#endif
Loading

0 comments on commit b2c4e00

Please sign in to comment.