#include <iostream>
#include "const_string.h"
#include "const_map.h"
#include <iostream>
#include "const_string.h"
#include "const_map.h"
namespace midi_details
{
using data_t = char;
using string_t = const_string<32>;
}
constexpr midi_details::data_t MIDI_NOTE_OFF = 8;
constexpr midi_details::data_t MIDI_NOTE_ON = 9;
constexpr midi_details::data_t MIDI_KEY_AFTERTOUCH = 10;
constexpr midi_details::data_t MIDI_CONTROL_CHANGE = 11;
constexpr midi_details::data_t MIDI_PROGRAM_CHANGE = 12;
constexpr midi_details::data_t MIDI_CHANNEL_AFTERTOUCH = 13;
constexpr midi_details::data_t MIDI_PITCH_WHEEL_CHANGE = 14;
namespace midi_details
{
constexpr auto required_bytes = make_const_map<data_t, data_t>({
{MIDI_NOTE_OFF,2},
{MIDI_NOTE_ON,2},
{MIDI_KEY_AFTERTOUCH,2},
{MIDI_CONTROL_CHANGE,2},
{MIDI_PROGRAM_CHANGE,1},
{MIDI_CHANNEL_AFTERTOUCH,1},
{MIDI_PITCH_WHEEL_CHANGE,2}
});
constexpr auto str = make_const_map<data_t, string_t>({
{ MIDI_NOTE_ON,"Note on" },
{ MIDI_NOTE_OFF,"Note off" },
{ MIDI_CONTROL_CHANGE, "Control change"},
{ MIDI_CHANNEL_AFTERTOUCH, "Channel aftertouch"},
{ MIDI_PITCH_WHEEL_CHANGE, "Pitch wheel change"}
});
struct info_t
{
constexpr info_t(data_t r, string_t n) :
required_bytes{ r },
name{ n }
{
}
data_t required_bytes;
string_t name;
};
} /* namespace midi_details */
constexpr auto midi(midi_details::data_t value)
{
return midi_details::info_t{ midi_details::required_bytes[value], midi_details::str[value] };
}
int main()
{
static_assert(MIDI_NOTE_OFF == 8);
static_assert(midi(MIDI_NOTE_OFF).required_bytes == 2, "test failed");
static_assert(midi(MIDI_NOTE_OFF).name == "Note off", "test failed");
return 0;
}
//---------------------------------------------------------------------------------------------------------------------
//
// const_map.h
// This header file implements a compile time map (key value pairs)
// it will take up n*sizeof(key-value pair) memory at compile time.
//
//---------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) 2021 Pepijn Kramer
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, version 3. (https://www.gnu.org/licenses/lgpl-3.0.en.html)
//
// This code is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#pragma once
#include "const_set.h"
template<typename key_t, typename value_t>
struct kv_pair_t final
{
kv_pair_t() = default;
constexpr kv_pair_t(const key_t& k, const value_t& v) :
key{ k },
value{ v }
{
};
key_t key{};
value_t value{};
constexpr bool operator>(const kv_pair_t& rhs) const
{
return key > rhs.key;
}
constexpr bool operator<(const kv_pair_t& rhs) const
{
return key < rhs.key;
}
constexpr bool operator==(const kv_pair_t& rhs) const
{
return key == rhs.key;
}
};
template<typename key_t, typename value_t, std::size_t N>
class const_map
{
public:
using pair_t = kv_pair_t<key_t, value_t>;
constexpr const_map(const pair_t(&pairs)[N]) :
m_set(pairs)
{
}
constexpr const value_t& operator[](const key_t& key) const
{
kv_pair_t<key_t, value_t> k{ key,{} };
return m_set[k].value;
}
private:
const_set<pair_t, N> m_set;
};
template<typename key_t, typename value_t, std::size_t N>
constexpr auto make_const_map(const kv_pair_t<key_t, value_t>(&pairs)[N])
{
return const_map<key_t, value_t, N>(pairs);
}
//---------------------------------------------------------------------------------------------------------------------
//
// const_set.h
//
// This header file implements a compile time ordered set
// Insertion will work in O(n) time
// The contains operation works in O(log n) time
// Adding a non unique value will result in a failure (std::invalid_argument exception)
//
//---------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) 2021 Pepijn Kramer
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, version 3. (https://www.gnu.org/licenses/lgpl-3.0.en.html)
//
// This code is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#pragma once
#include <cassert>
#include <stdexcept>
//---------------------------------------------------------------------------------------------------------------------
namespace details
{
// helper struct, determines a span in which to look for a value
struct span_t
{
constexpr span_t(const size_t new_from, const size_t new_to) :
from{ new_from },
to{ new_to },
mid{ (from + to) / 2 }
{
}
constexpr span_t left()
{
size_t new_to = (mid > to) ? mid - 1 : mid;
return span_t(from, new_to);
}
constexpr span_t right()
{
size_t new_from = (from < mid) ? mid : mid + 1;
return span_t(new_from, to);
}
size_t from;
size_t to;
size_t mid;
};
}
//---------------------------------------------------------------------------------------------------------------------
template<typename type_t, std::size_t N>
class const_set
{
public:
constexpr const_set(const type_t(&list)[N]) :
m_values{}
{
for (const auto& v : list) insert(v);
}
// add begin end operations so collection can be used in range based for loops
constexpr auto begin() const
{
return std::begin(m_values);
}
constexpr auto end() const
{
return std::end(m_values);
}
constexpr bool contains(const type_t& value) const
{
details::span_t span{ 0, N - 1 };
do
{
if (m_values[span.mid] == value)
{
return true;
}
span = (value > m_values[span.mid]) ? span.right() : span.left();
assert(span.mid < N);
} while (span.from != span.to);
return (m_values[span.mid] == value);
}
constexpr const type_t& operator[](const type_t& value) const
{
details::span_t span{ 0, N - 1 };
do
{
if (m_values[span.mid] == value)
{
return m_values[span.mid];
}
span = (value > m_values[span.mid]) ? span.right() : span.left();
assert(span.mid < N);
} while (span.from != span.to);
return (m_values[span.mid] == value) ? m_values[span.mid] : default_value;
}
private:
// insert in ascending order, doesn't have to be very smart
// only done at compile time.
inline constexpr void insert(const type_t& value)
{
std::size_t pos{ 0 };
if (m_size != 0)
{
while ((pos < m_size) && (value > m_values[pos])) pos++;
if (m_values[pos] == value) //
{
throw std::invalid_argument("value is not unique, set cannot be build");
}
// shift content to back
if (pos < m_size)
{
for (std::size_t m = N - 1; m > pos; --m)
{
m_values[m] = std::move(m_values[m - 1]);
}
}
}
m_values[pos] = value;
++m_size;
}
type_t m_values[N];
type_t default_value{};
std::size_t m_size = 0;
};
template<typename type_t, std::size_t N>
constexpr auto make_const_set(const type_t(&list)[N])
{
return const_set<type_t, N>(list);
}
//---------------------------------------------------------------------------------------------------------------------
//
// const_string.h
//
// This header file implements a minimal compile time constant string
//
//---------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) 2021 Pepijn Kramer
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, version 3. (https://www.gnu.org/licenses/lgpl-3.0.en.html)
//
// This code is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#pragma once
#include <algorithm>
#include <array>
#include <iostream>
//-------------------------------------------------------------------------------------------------
// Helper class to hold a string of maximum capacity at compile time.
template<std::size_t string_capacity_v = 128>
class const_string
{
public:
constexpr const_string() = default;
~const_string() = default;
constexpr const_string(const const_string&) = default;
template<std::size_t string_length>
constexpr const_string(const char(&str)[string_length]) :
m_str{}
{
for (std::size_t n = 0; n < std::min(string_capacity_v, string_length); ++n) m_str[n] = str[n];
}
constexpr const char* c_str() const noexcept
{
return m_str;
}
constexpr std::size_t capacity() const noexcept
{
return string_capacity_v;
}
private:
char m_str[string_capacity_v]{};
};
template<std::size_t string_capacity_v>
constexpr bool operator==(const const_string<string_capacity_v>& lhs, const const_string<string_capacity_v>& rhs)
{
std::size_t n = 0;
auto l = lhs.c_str();
auto r = rhs.c_str();
while ((l[n] == r[n]) && (n < string_capacity_v) && (l[n] != 0) && (r[n] != 0) ) ++n;
return l[n] == r[n];
}
template<std::size_t string_capacity_v, std::size_t str_len>
constexpr bool operator==(const const_string<string_capacity_v>& lhs, const char(&rhs)[str_len])
{
std::size_t n = 0;
auto rstr = const_string<string_capacity_v>(rhs);
return (lhs == rstr);
}
template<std::size_t string_capacity_v>
std::ostream& operator<<(std::ostream& os, const const_string<string_capacity_v>& cstr)
{
return os << cstr.str();
}