aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/types/HasIdentifier.hpp
blob: bbd9771e35ad4bad8fc44cf9a2c01e408aadaf9b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#pragma once

#include <algorithm>
#include <cassert>
#include <string>
#include <string_view>
#include <ostream>

#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/utility/Getters.hpp"

namespace OpenVic {
   constexpr bool valid_basic_identifier_char(char c) {
      return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_';
   }
   constexpr bool valid_basic_identifier(std::string_view identifier) {
      return std::all_of(identifier.begin(), identifier.end(), valid_basic_identifier_char);
   }
   constexpr std::string_view extract_basic_identifier_prefix(std::string_view identifier) {
      size_t len = 0;
      while (len < identifier.size() && valid_basic_identifier_char(identifier[len])) {
         ++len;
      }
      return { identifier.data(), len };
   }

   /*
    * Base class for objects with a non-empty string identifier. Uniquely named instances of a type derived from this class
    * can be entered into an IdentifierRegistry instance.
    */
   class HasIdentifier {
      /* Not const so it can be moved rather than needing to be copied. */
      std::string PROPERTY(identifier);

   protected:
      HasIdentifier(std::string_view new_identifier): identifier { new_identifier } {
         assert(!identifier.empty());
      }
      HasIdentifier(HasIdentifier const&) = default;

   public:
      HasIdentifier(HasIdentifier&&) = default;
      HasIdentifier& operator=(HasIdentifier const&) = delete;
      HasIdentifier& operator=(HasIdentifier&&) = delete;
   };

   inline std::ostream& operator<<(std::ostream& stream, HasIdentifier const& obj) {
      return stream << obj.get_identifier();
   }
   inline std::ostream& operator<<(std::ostream& stream, HasIdentifier const* obj) {
      return obj != nullptr ? stream << *obj : stream << "<NULL>";
   }

   template<typename T>
   concept HasGetIdentifier = requires(T const& t) {
      { t.get_identifier() } -> std::same_as<std::string_view>;
   };

   /*
    * Base class for objects with associated colour information.
    */
   template<IsColour ColourT>
   class _HasColour {
      const ColourT PROPERTY(colour);

   protected:
      _HasColour(ColourT new_colour, bool cannot_be_null): colour { new_colour } {
         assert(!cannot_be_null || !colour.is_null());
      }
      _HasColour(_HasColour const&) = default;

   public:
      _HasColour(_HasColour&&) = default;
      _HasColour& operator=(_HasColour const&) = delete;
      _HasColour& operator=(_HasColour&&) = delete;
   };

   using HasColour = _HasColour<colour_t>;
   using HasAlphaColour = _HasColour<colour_argb_t>;

   template<typename T>
   concept HasGetColour = requires(T const& t) {
      { t.get_colour() } -> IsColour;
   };

   /*
    * Base class for objects with a unique string identifier and associated colour information.
    */
   template<IsColour ColourT>
   class _HasIdentifierAndColour : public HasIdentifier, public _HasColour<ColourT> {
   protected:
      _HasIdentifierAndColour(std::string_view new_identifier, ColourT new_colour, bool cannot_be_null)
         : HasIdentifier { new_identifier }, _HasColour<ColourT> { new_colour, cannot_be_null } {}
      _HasIdentifierAndColour(_HasIdentifierAndColour const&) = default;

   public:
      _HasIdentifierAndColour(_HasIdentifierAndColour&&) = default;
      _HasIdentifierAndColour& operator=(_HasIdentifierAndColour const&) = delete;
      _HasIdentifierAndColour& operator=(_HasIdentifierAndColour&&) = delete;
   };

   using HasIdentifierAndColour = _HasIdentifierAndColour<colour_t>;
   using HasIdentifierAndAlphaColour = _HasIdentifierAndColour<colour_argb_t>;

   template<typename T>
   concept HasGetIdentifierAndGetColour = HasGetIdentifier<T> && HasGetColour<T>;

   template<std::unsigned_integral T = size_t>
   class HasIndex {
   public:
      using index_t = T;

   private:
      const index_t PROPERTY(index);

   protected:
      HasIndex(index_t new_index) : index { new_index } {}
      HasIndex(HasIndex const&) = default;

   public:
      HasIndex(HasIndex&&) = default;
      HasIndex& operator=(HasIndex const&) = delete;
      HasIndex& operator=(HasIndex&&) = delete;
   };

   template<typename T>
   concept HasGetIndex = requires(T const& t) {
      { t.get_index() } -> std::unsigned_integral;
   };
}